dhcp.c revision 47d708b8f4e037f6f224f71ea5864c90184b4ffb
1d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan/* 2d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * dhcpcd - DHCP client daemon 3d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * Copyright (c) 2006-2015 Roy Marples <roy@marples.name> 4d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * All rights reserved 5d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 6d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * Redistribution and use in source and binary forms, with or without 7d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * modification, are permitted provided that the following conditions 8d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * are met: 9d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * 1. Redistributions of source code must retain the above copyright 10d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * notice, this list of conditions and the following disclaimer. 11d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * 2. Redistributions in binary form must reproduce the above copyright 12d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * notice, this list of conditions and the following disclaimer in the 13d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * documentation and/or other materials provided with the distribution. 14d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * 15d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * SUCH DAMAGE. 26d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan */ 27d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 28d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <sys/param.h> 29d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <sys/socket.h> 30d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <sys/stat.h> 31d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 32d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <arpa/inet.h> 33d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <net/if.h> 34d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <net/route.h> 35d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <netinet/if_ether.h> 36d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <netinet/in_systm.h> 37d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <netinet/in.h> 38d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <netinet/ip.h> 39d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define __FAVOR_BSD /* Nasty glibc hack so we can use BSD semantics for UDP */ 40d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <netinet/udp.h> 41d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#undef __FAVOR_BSD 42d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 43d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <ctype.h> 44d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <errno.h> 45d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <fcntl.h> 46d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <inttypes.h> 47d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <stddef.h> 48d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <stdlib.h> 49d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <string.h> 50d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <unistd.h> 51d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 52d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define ELOOP_QUEUE 2 53d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "config.h" 54d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "arp.h" 55d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "common.h" 56d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "dhcp.h" 57d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "dhcpcd.h" 58d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "dhcp-common.h" 59d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "duid.h" 60d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "eloop.h" 61d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "if.h" 62d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "ipv4.h" 63d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "ipv4ll.h" 6423ff6edd8b4ec796a32d36a3eca8a8d8c785b565Samuel Tan#include "rpc-interface.h" 65d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "script.h" 66d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 67d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define DAD "Duplicate address detected" 68d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define DHCP_MIN_LEASE 20 69d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 70d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define IPV4A ADDRIPV4 | ARRAY 71d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define IPV4R ADDRIPV4 | REQUEST 72d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 73d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan/* We should define a maximum for the NAK exponential backoff */ 74d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define NAKOFF_MAX 60 75d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 76d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan/* Wait N nanoseconds between sending a RELEASE and dropping the address. 77d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * This gives the kernel enough time to actually send it. */ 78d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define RELEASE_DELAY_S 0 79d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define RELEASE_DELAY_NS 10000000 80d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 81d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifndef IPDEFTTL 82d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define IPDEFTTL 64 /* RFC1340 */ 83d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif 84d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 85d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstruct dhcp_op { 86d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan uint8_t value; 87d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan const char *name; 88d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}; 89d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 90d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic const struct dhcp_op dhcp_ops[] = { 91d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { DHCP_DISCOVER, "DISCOVER" }, 92d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { DHCP_OFFER, "OFFER" }, 93d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { DHCP_REQUEST, "REQUEST" }, 94d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { DHCP_DECLINE, "DECLINE" }, 95d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { DHCP_ACK, "ACK" }, 96d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { DHCP_NAK, "NAK" }, 97d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { DHCP_RELEASE, "RELEASE" }, 98d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { DHCP_INFORM, "INFORM" }, 99d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { DHCP_FORCERENEW, "DHCP_FORCERENEW"}, 100d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { 0, NULL } 101d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}; 102d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 103d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic const char * const dhcp_params[] = { 104d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "ip_address", 105d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "subnet_cidr", 106d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "network_number", 107d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "filename", 108d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "server_name", 109d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan NULL 110d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}; 111d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 112d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstruct udp_dhcp_packet 113d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 114d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct ip ip; 115d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct udphdr udp; 116d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct dhcp_message dhcp; 117d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}; 118d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 119d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic const size_t udp_dhcp_len = sizeof(struct udp_dhcp_packet); 120d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 121d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int dhcp_open(struct interface *ifp); 122d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 123d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanvoid 124d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_printoptions(const struct dhcpcd_ctx *ctx, 125d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan const struct dhcp_opt *opts, size_t opts_len) 126d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 127d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan const char * const *p; 128d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan size_t i, j; 129d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan const struct dhcp_opt *opt, *opt2; 130d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan int cols; 131d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 132d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan for (p = dhcp_params; *p; p++) 133d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan printf(" %s\n", *p); 134d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 135d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan for (i = 0, opt = ctx->dhcp_opts; i < ctx->dhcp_opts_len; i++, opt++) { 136d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan for (j = 0, opt2 = opts; j < opts_len; j++, opt2++) 137d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (opt->option == opt2->option) 138d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan break; 139d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (j == opts_len) { 140d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan cols = printf("%03d %s", opt->option, opt->var); 141d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_print_option_encoding(opt, cols); 142d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 143d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 144d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan for (i = 0, opt = opts; i < opts_len; i++, opt++) { 145d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan cols = printf("%03d %s", opt->option, opt->var); 146d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_print_option_encoding(opt, cols); 147d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 148d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 149d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 150d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define get_option_raw(ctx, dhcp, opt) get_option(ctx, dhcp, opt, NULL) 151d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic const uint8_t * 152d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanget_option(struct dhcpcd_ctx *ctx, 153d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan const struct dhcp_message *dhcp, unsigned int opt, size_t *len) 154d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 155d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan const uint8_t *p = dhcp->options; 156d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan const uint8_t *e = p + sizeof(dhcp->options); 157d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan uint8_t l, ol = 0; 158d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan uint8_t o = 0; 159d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan uint8_t overl = 0; 160d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan uint8_t *bp = NULL; 161d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan const uint8_t *op = NULL; 162d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan size_t bl = 0; 163d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 164d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* Check we have the magic cookie */ 165d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (dhcp->cookie != htonl(MAGIC_COOKIE)) { 166d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan errno = ENOTSUP; 167d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return NULL; 168d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 169d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1709ae79b8946de6ac1e295417875f2ac7316dd0f80Samuel Tan /* DHCP options are in TLV format with T and L each being a single 1719ae79b8946de6ac1e295417875f2ac7316dd0f80Samuel Tan * bytes. In general, here we have p -> T, ol=p+1 -> L, op -> V. 1729ae79b8946de6ac1e295417875f2ac7316dd0f80Samuel Tan * We must make sure there is enough room to read both T and L. 1739ae79b8946de6ac1e295417875f2ac7316dd0f80Samuel Tan */ 1749ae79b8946de6ac1e295417875f2ac7316dd0f80Samuel Tan while (p + 1 < e) { 175d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan o = *p++; 176d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (o == opt) { 177d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (op) { 178d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (!ctx->opt_buffer) { 179d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ctx->opt_buffer = 180d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan malloc(DHCP_OPTION_LEN + 181d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan BOOTFILE_LEN + SERVERNAME_LEN); 182d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ctx->opt_buffer == NULL) 183d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return NULL; 184d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 185d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (!bp) 186d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan bp = ctx->opt_buffer; 187d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan memcpy(bp, op, ol); 188d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan bp += ol; 189d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 1909ae79b8946de6ac1e295417875f2ac7316dd0f80Samuel Tan ol = (p + *p < e) ? *p : e - (p + 1); 191d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (p + ol > e) { 192d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan errno = EINVAL; 193d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return NULL; 194d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 195d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan op = p + 1; 196d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan bl += ol; 197d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 198d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan switch (o) { 199d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan case DHO_PAD: 200d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan continue; 201d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan case DHO_END: 202d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (overl & 1) { 203d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* bit 1 set means parse boot file */ 204d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan overl = (uint8_t)(overl & ~1); 205d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p = dhcp->bootfile; 206d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan e = p + sizeof(dhcp->bootfile); 207d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } else if (overl & 2) { 208d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* bit 2 set means parse server name */ 209d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan overl = (uint8_t)(overl & ~2); 210d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p = dhcp->servername; 211d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan e = p + sizeof(dhcp->servername); 212d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } else 213d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan goto exit; 214d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan break; 215d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan case DHO_OPTIONSOVERLOADED: 216d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* Ensure we only get this option once by setting 217d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * the last bit as well as the value. 218d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * This is valid because only the first two bits 219d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * actually mean anything in RFC2132 Section 9.3 */ 220d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (!overl) 221d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan overl = 0x80 | p[1]; 222d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan break; 223d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 224d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan l = *p++; 225d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p += l; 226d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 227d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 228d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanexit: 229d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (len) 230d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *len = bl; 231d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (bp) { 232d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan memcpy(bp, op, ol); 233d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return (const uint8_t *)ctx->opt_buffer; 234d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 235d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (op) 236d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return op; 237d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan errno = ENOENT; 238d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return NULL; 239d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 240d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 241d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanint 242d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanget_option_addr(struct dhcpcd_ctx *ctx, 243d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct in_addr *a, const struct dhcp_message *dhcp, 244d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan uint8_t option) 245d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 246d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan const uint8_t *p; 247d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan size_t len; 248d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 249d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p = get_option(ctx, dhcp, option, &len); 250d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (!p || len < (ssize_t)sizeof(a->s_addr)) 251d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return -1; 252d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan memcpy(&a->s_addr, p, sizeof(a->s_addr)); 253d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return 0; 254d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 255d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 256d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int 257d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanget_option_uint32(struct dhcpcd_ctx *ctx, 258d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan uint32_t *i, const struct dhcp_message *dhcp, uint8_t option) 259d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 260d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan const uint8_t *p; 261d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan size_t len; 262d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan uint32_t d; 263d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 264d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p = get_option(ctx, dhcp, option, &len); 265d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (!p || len < (ssize_t)sizeof(d)) 266d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return -1; 267d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan memcpy(&d, p, sizeof(d)); 268d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (i) 269d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *i = ntohl(d); 270d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return 0; 271d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 272d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 273d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int 274d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanget_option_uint8(struct dhcpcd_ctx *ctx, 275d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan uint8_t *i, const struct dhcp_message *dhcp, uint8_t option) 276d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 277d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan const uint8_t *p; 278d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan size_t len; 279d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 280d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p = get_option(ctx, dhcp, option, &len); 281d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (!p || len < (ssize_t)sizeof(*p)) 282d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return -1; 283d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (i) 284d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *i = *(p); 285d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return 0; 286d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 287d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 288d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanssize_t 289d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandecode_rfc3442(char *out, size_t len, const uint8_t *p, size_t pl) 290d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 291d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan const uint8_t *e; 292d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan size_t bytes = 0, ocets; 293d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan int b; 294d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan uint8_t cidr; 295d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct in_addr addr; 296d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan char *o = out; 297d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 298d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* Minimum is 5 -first is CIDR and a router length of 4 */ 299d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (pl < 5) { 300d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan errno = EINVAL; 301d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return -1; 302d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 303d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 304d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan e = p + pl; 305d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan while (p < e) { 306d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan cidr = *p++; 307d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (cidr > 32) { 308d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan errno = EINVAL; 309d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return -1; 310d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 311d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ocets = (size_t)(cidr + 7) / NBBY; 312d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (p + 4 + ocets > e) { 313d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan errno = ERANGE; 314d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return -1; 315d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 316d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (!out) { 317d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p += 4 + ocets; 318d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan bytes += ((4 * 4) * 2) + 4; 319d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan continue; 320d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 321d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if ((((4 * 4) * 2) + 4) > len) { 322d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan errno = ENOBUFS; 323d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return -1; 324d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 325d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (o != out) { 326d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *o++ = ' '; 327d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan len--; 328d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 329d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* If we have ocets then we have a destination and netmask */ 330d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ocets > 0) { 331d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan addr.s_addr = 0; 332d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan memcpy(&addr.s_addr, p, ocets); 333d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan b = snprintf(o, len, "%s/%d", inet_ntoa(addr), cidr); 334d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p += ocets; 335d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } else 336d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan b = snprintf(o, len, "0.0.0.0/0"); 337d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan o += b; 338d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan len -= (size_t)b; 339d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 340d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* Finally, snag the router */ 341d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan memcpy(&addr.s_addr, p, 4); 342d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p += 4; 343d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan b = snprintf(o, len, " %s", inet_ntoa(addr)); 344d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan o += b; 345d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan len -= (size_t)b; 346d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 347d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 348d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (out) 349d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return o - out; 350d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return (ssize_t)bytes; 351d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 352d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 353d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic struct rt_head * 354d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandecode_rfc3442_rt(struct dhcpcd_ctx *ctx, const uint8_t *data, size_t dl) 355d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 356d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan const uint8_t *p = data; 357d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan const uint8_t *e; 358d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan uint8_t cidr; 359d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan size_t ocets; 360d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct rt_head *routes; 361d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct rt *rt = NULL; 362d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 363d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* Minimum is 5 -first is CIDR and a router length of 4 */ 364d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (dl < 5) 365d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return NULL; 366d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 367d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan routes = malloc(sizeof(*routes)); 368d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan TAILQ_INIT(routes); 369d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan e = p + dl; 370d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan while (p < e) { 371d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan cidr = *p++; 372d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (cidr > 32) { 373d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ipv4_freeroutes(routes); 374d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan errno = EINVAL; 375d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return NULL; 376d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 377d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 378d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ocets = (size_t)(cidr + 7) / NBBY; 379d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (p + 4 + ocets > e) { 380d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ipv4_freeroutes(routes); 381d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan errno = ERANGE; 382d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return NULL; 383d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 384d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 385d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan rt = calloc(1, sizeof(*rt)); 386d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (rt == NULL) { 387d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ctx, LOG_ERR, "%s: %m", __func__); 388d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ipv4_freeroutes(routes); 389d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return NULL; 390d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 391d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan TAILQ_INSERT_TAIL(routes, rt, next); 392d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 393d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* If we have ocets then we have a destination and netmask */ 394d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ocets > 0) { 395d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan memcpy(&rt->dest.s_addr, p, ocets); 396d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p += ocets; 397d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan rt->net.s_addr = htonl(~0U << (32 - cidr)); 398d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 399d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 400d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* Finally, snag the router */ 401d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan memcpy(&rt->gate.s_addr, p, 4); 402d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p += 4; 403d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 404d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return routes; 405d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 406d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 407d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanchar * 408d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandecode_rfc3361(const uint8_t *data, size_t dl) 409d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 410d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan uint8_t enc; 411d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan size_t l; 412d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ssize_t r; 413d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan char *sip = NULL; 414d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct in_addr addr; 415d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan char *p; 416d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 417d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (dl < 2) { 418d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan errno = EINVAL; 419d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return 0; 420d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 421d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 422d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan enc = *data++; 423d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dl--; 424d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan switch (enc) { 425d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan case 0: 426d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if ((r = decode_rfc3397(NULL, 0, data, dl)) > 0) { 427d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan l = (size_t)r; 428d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan sip = malloc(l); 429d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (sip == NULL) 430d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return 0; 431d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan decode_rfc3397(sip, l, data, dl); 432d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 433d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan break; 434d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan case 1: 435d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (dl == 0 || dl % 4 != 0) { 436d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan errno = EINVAL; 437d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan break; 438d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 439d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan addr.s_addr = INADDR_BROADCAST; 440d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan l = ((dl / sizeof(addr.s_addr)) * ((4 * 4) + 1)) + 1; 441d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan sip = p = malloc(l); 442d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (sip == NULL) 443d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return 0; 444d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan while (dl != 0) { 445d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan memcpy(&addr.s_addr, data, sizeof(addr.s_addr)); 446d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan data += sizeof(addr.s_addr); 447d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p += snprintf(p, l - (size_t)(p - sip), 448d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%s ", inet_ntoa(addr)); 449d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dl -= sizeof(addr.s_addr); 450d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 451d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *--p = '\0'; 452d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan break; 453d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan default: 454d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan errno = EINVAL; 455d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return 0; 456d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 457d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 458d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return sip; 459d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 460d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 461d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan/* Decode an RFC5969 6rd order option into a space 462d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * separated string. Returns length of string (including 463d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * terminating zero) or zero on error. */ 464d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanssize_t 465d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandecode_rfc5969(char *out, size_t len, const uint8_t *p, size_t pl) 466d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 467d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan uint8_t ipv4masklen, ipv6prefixlen; 468d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan uint8_t ipv6prefix[16]; 469d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan uint8_t br[4]; 470d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan int i; 471d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ssize_t b, bytes = 0; 472d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 473d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (pl < 22) { 474d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan errno = EINVAL; 475d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return 0; 476d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 477d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 478d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ipv4masklen = *p++; 479d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan pl--; 480d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ipv6prefixlen = *p++; 481d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan pl--; 482d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 483d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan for (i = 0; i < 16; i++) { 484d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ipv6prefix[i] = *p++; 485d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan pl--; 486d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 487d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (out) { 488d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan b= snprintf(out, len, 489d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%d %d " 490d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%02x%02x:%02x%02x:" 491d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%02x%02x:%02x%02x:" 492d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%02x%02x:%02x%02x:" 493d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%02x%02x:%02x%02x", 494d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ipv4masklen, ipv6prefixlen, 495d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ipv6prefix[0], ipv6prefix[1], ipv6prefix[2], ipv6prefix[3], 496d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ipv6prefix[4], ipv6prefix[5], ipv6prefix[6], ipv6prefix[7], 497d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ipv6prefix[8], ipv6prefix[9], ipv6prefix[10],ipv6prefix[11], 498d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ipv6prefix[12],ipv6prefix[13],ipv6prefix[14], ipv6prefix[15] 499d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ); 500d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 501d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan len -= (size_t)b; 502d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan out += b; 503d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan bytes += b; 504d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } else { 505d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan bytes += 16 * 2 + 8 + 2 + 1 + 2; 506d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 507d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 508d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan while (pl >= 4) { 509d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan br[0] = *p++; 510d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan br[1] = *p++; 511d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan br[2] = *p++; 512d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan br[3] = *p++; 513d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan pl -= 4; 514d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 515d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (out) { 516d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan b= snprintf(out, len, " %d.%d.%d.%d", 517d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan br[0], br[1], br[2], br[3]); 518d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan len -= (size_t)b; 519d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan out += b; 520d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan bytes += b; 521d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } else { 522d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan bytes += (4 * 4); 523d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 524d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 525d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 526d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return bytes; 527d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 528d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 529d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic char * 530d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanget_option_string(struct dhcpcd_ctx *ctx, 531d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan const struct dhcp_message *dhcp, uint8_t option) 532d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 533d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan size_t len; 534d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan const uint8_t *p; 535d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan char *s; 536d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 537d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p = get_option(ctx, dhcp, option, &len); 538d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (!p || len == 0 || *p == '\0') 539d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return NULL; 540d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 541d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan s = malloc(sizeof(char) * (len + 1)); 542d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (s) { 543d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan memcpy(s, p, len); 544d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan s[len] = '\0'; 545d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 546d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return s; 547d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 548d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 549d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan/* This calculates the netmask that we should use for static routes. 550d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * This IS different from the calculation used to calculate the netmask 551d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * for an interface address. */ 552d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic uint32_t 553d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanroute_netmask(uint32_t ip_in) 554d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 555d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* used to be unsigned long - check if error */ 556d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan uint32_t p = ntohl(ip_in); 557d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan uint32_t t; 558d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 559d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (IN_CLASSA(p)) 560d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan t = ~IN_CLASSA_NET; 561d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan else { 562d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (IN_CLASSB(p)) 563d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan t = ~IN_CLASSB_NET; 564d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan else { 565d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (IN_CLASSC(p)) 566d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan t = ~IN_CLASSC_NET; 567d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan else 568d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan t = 0; 569d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 570d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 571d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 572d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan while (t & p) 573d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan t >>= 1; 574d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 575d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return (htonl(~t)); 576d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 577d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 578d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan/* We need to obey routing options. 579d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * If we have a CSR then we only use that. 580d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * Otherwise we add static routes and then routers. */ 581d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstruct rt_head * 582d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanget_option_routes(struct interface *ifp, const struct dhcp_message *dhcp) 583d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 584d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct if_options *ifo = ifp->options; 585d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan const uint8_t *p; 586d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan const uint8_t *e; 587d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct rt_head *routes = NULL; 588d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct rt *route = NULL; 589d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan size_t len; 590d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan const char *csr = ""; 591d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 592d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* If we have CSR's then we MUST use these only */ 593d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (!has_option_mask(ifo->nomask, DHO_CSR)) 594d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p = get_option(ifp->ctx, dhcp, DHO_CSR, &len); 595d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan else 596d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p = NULL; 597d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* Check for crappy MS option */ 598d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (!p && !has_option_mask(ifo->nomask, DHO_MSCSR)) { 599d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p = get_option(ifp->ctx, dhcp, DHO_MSCSR, &len); 600d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (p) 601d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan csr = "MS "; 602d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 603d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (p) { 604d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan routes = decode_rfc3442_rt(ifp->ctx, p, len); 605d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (routes) { 606d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan const struct dhcp_state *state; 607d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 608d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state = D_CSTATE(ifp); 609d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (!(ifo->options & DHCPCD_CSR_WARNED) && 610d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan !(state->added & STATE_FAKE)) 611d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { 612d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_DEBUG, 613d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%s: using %sClassless Static Routes", 614d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->name, csr); 615d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifo->options |= DHCPCD_CSR_WARNED; 616d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 617d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return routes; 618d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 619d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 620d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 621d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* OK, get our static routes first. */ 622d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan routes = malloc(sizeof(*routes)); 623d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (routes == NULL) { 624d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_ERR, "%s: %m", __func__); 625d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return NULL; 626d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 627d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan TAILQ_INIT(routes); 628d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (!has_option_mask(ifo->nomask, DHO_STATICROUTE)) 629d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p = get_option(ifp->ctx, dhcp, DHO_STATICROUTE, &len); 630d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan else 631d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p = NULL; 632d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* RFC 2131 Section 5.8 states length MUST be in multiples of 8 */ 633d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (p && len % 8 == 0) { 634d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan e = p + len; 635d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan while (p < e) { 636d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if ((route = calloc(1, sizeof(*route))) == NULL) { 637d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_ERR, "%s: %m", __func__); 638d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ipv4_freeroutes(routes); 639d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return NULL; 640d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 641d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan memcpy(&route->dest.s_addr, p, 4); 642d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p += 4; 643d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan memcpy(&route->gate.s_addr, p, 4); 644d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p += 4; 645d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* RFC 2131 Section 5.8 states default route is 646d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * illegal */ 647d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (route->dest.s_addr == htonl(INADDR_ANY)) { 648d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan errno = EINVAL; 649d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan free(route); 650d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan continue; 651d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 652d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan route->net.s_addr = route_netmask(route->dest.s_addr); 653d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan TAILQ_INSERT_TAIL(routes, route, next); 654d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 655d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 656d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 657d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* Now grab our routers */ 658d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (!has_option_mask(ifo->nomask, DHO_ROUTER)) 659d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p = get_option(ifp->ctx, dhcp, DHO_ROUTER, &len); 660d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan else 661d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p = NULL; 662d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (p) { 663d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan e = p + len; 664d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan while (p < e) { 665d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if ((route = calloc(1, sizeof(*route))) == NULL) { 666d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_ERR, "%s: %m", __func__); 667d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ipv4_freeroutes(routes); 668d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return NULL; 669d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 670d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan memcpy(&route->gate.s_addr, p, 4); 671d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p += 4; 672d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan TAILQ_INSERT_TAIL(routes, route, next); 673d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 674d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 675d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 676d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return routes; 677d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 678d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 679d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define PUTADDR(_type, _val) \ 680d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { \ 681d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *p++ = _type; \ 682d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *p++ = 4; \ 683d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan memcpy(p, &_val.s_addr, 4); \ 684d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p += 4; \ 685d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 686d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 687d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanint 688d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_message_add_addr(struct dhcp_message *dhcp, 689d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan uint8_t type, struct in_addr addr) 690d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 691d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan uint8_t *p; 692d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan size_t len; 693d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 694d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p = dhcp->options; 695d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan while (*p != DHO_END) { 696d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p++; 697d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p += *p + 1; 698d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 699d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 700d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan len = (size_t)(p - (uint8_t *)dhcp); 701d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (len + 6 > sizeof(*dhcp)) { 702d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan errno = ENOMEM; 703d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return -1; 704d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 705d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 706d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan PUTADDR(type, addr); 707d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *p = DHO_END; 708d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return 0; 709d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 710d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 711d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanssize_t 712d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanmake_message(struct dhcp_message **message, 713d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan const struct interface *ifp, 714d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan uint8_t type) 715d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 716d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct dhcp_message *dhcp; 717d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan uint8_t *m, *lp, *p, *auth; 718d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan uint8_t *n_params = NULL, auth_len; 719d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan uint32_t ul; 720d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan uint16_t sz; 721d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan size_t len, i; 722d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan const struct dhcp_opt *opt; 723d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct if_options *ifo = ifp->options; 724d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan const struct dhcp_state *state = D_CSTATE(ifp); 725d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan const struct dhcp_lease *lease = &state->lease; 726d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan time_t up = uptime() - state->start_uptime; 727d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan char hbuf[HOSTNAME_MAX_LEN + 1]; 728d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan const char *hostname; 729d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan const struct vivco *vivco; 730d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 731d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp = calloc(1, sizeof (*dhcp)); 732d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (dhcp == NULL) 733d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return -1; 734d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan m = (uint8_t *)dhcp; 735d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p = dhcp->options; 736d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 737d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if ((type == DHCP_INFORM || type == DHCP_RELEASE || 738d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan (type == DHCP_REQUEST && 739d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->net.s_addr == lease->net.s_addr && 740d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan (state->new == NULL || 741d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->new->cookie == htonl(MAGIC_COOKIE))))) 742d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { 743d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp->ciaddr = state->addr.s_addr; 744d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* In-case we haven't actually configured the address yet */ 745d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (type == DHCP_INFORM && state->addr.s_addr == 0) 746d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp->ciaddr = lease->addr.s_addr; 747d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 748d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 749d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp->op = DHCP_BOOTREQUEST; 750d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp->hwtype = (uint8_t)ifp->family; 751d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan switch (ifp->family) { 752d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan case ARPHRD_ETHER: 753d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan case ARPHRD_IEEE802: 754d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp->hwlen = (uint8_t)ifp->hwlen; 755d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan memcpy(&dhcp->chaddr, &ifp->hwaddr, ifp->hwlen); 756d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan break; 757d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 758d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 759d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifo->options & DHCPCD_BROADCAST && 760d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp->ciaddr == 0 && 761d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan type != DHCP_DECLINE && 762d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan type != DHCP_RELEASE) 763d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp->flags = htons(BROADCAST_FLAG); 764d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 765d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (type != DHCP_DECLINE && type != DHCP_RELEASE) { 766d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (up < 0 || up > (time_t)UINT16_MAX) 767d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp->secs = htons((uint16_t)UINT16_MAX); 768d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan else 769d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp->secs = htons((uint16_t)up); 770d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 771d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp->xid = htonl(state->xid); 772d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp->cookie = htonl(MAGIC_COOKIE); 773d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 774d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (!(ifo->options & DHCPCD_BOOTP)) { 775d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *p++ = DHO_MESSAGETYPE; 776d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *p++ = 1; 777d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *p++ = type; 778d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 779d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 780d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state->clientid) { 781d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *p++ = DHO_CLIENTID; 782d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan memcpy(p, state->clientid, (size_t)state->clientid[0] + 1); 783d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p += state->clientid[0] + 1; 784d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 785d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 786d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (lease->addr.s_addr && lease->cookie == htonl(MAGIC_COOKIE)) { 787d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (type == DHCP_DECLINE || 788d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan (type == DHCP_REQUEST && 789d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan lease->addr.s_addr != state->addr.s_addr)) 790d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { 791d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan PUTADDR(DHO_IPADDRESS, lease->addr); 792d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (lease->server.s_addr) 793d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan PUTADDR(DHO_SERVERID, lease->server); 794d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 795d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 796d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (type == DHCP_RELEASE) { 797d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (lease->server.s_addr) 798d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan PUTADDR(DHO_SERVERID, lease->server); 799d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 800d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 801d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 802d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (type == DHCP_DECLINE) { 803d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *p++ = DHO_MESSAGE; 804d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan len = strlen(DAD); 805d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *p++ = (uint8_t)len; 806d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan memcpy(p, DAD, len); 807d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p += len; 808d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 809d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 810d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (type == DHCP_DISCOVER && 811d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan !(ifp->ctx->options & DHCPCD_TEST) && 812d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan has_option_mask(ifo->requestmask, DHO_RAPIDCOMMIT)) 813d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { 814d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* RFC 4039 Section 3 */ 815d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *p++ = DHO_RAPIDCOMMIT; 816d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *p++ = 0; 817d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 818d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 819d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (type == DHCP_DISCOVER && ifo->options & DHCPCD_REQUEST) 820d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan PUTADDR(DHO_IPADDRESS, ifo->req_addr); 821d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 822d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* RFC 2563 Auto Configure */ 823d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (type == DHCP_DISCOVER && ifo->options & DHCPCD_IPV4LL) { 824d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *p++ = DHO_AUTOCONFIGURE; 825d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *p++ = 1; 826d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *p++ = 1; 827d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 828d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 829d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (type == DHCP_DISCOVER || 830d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan type == DHCP_INFORM || 831d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan type == DHCP_REQUEST) 832d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { 833d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (!(ifo->options & DHCPCD_BOOTP)) { 834d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan int mtu; 835d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 836d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *p++ = DHO_MAXMESSAGESIZE; 837d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *p++ = 2; 838d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan mtu = if_getmtu(ifp->name); 839d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (mtu < MTU_MIN) { 840d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (if_setmtu(ifp->name, MTU_MIN) == 0) 841d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan sz = MTU_MIN; 842d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } else if (mtu > MTU_MAX) { 843d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* Even though our MTU could be greater than 844d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * MTU_MAX (1500) dhcpcd does not presently 845d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * handle DHCP packets any bigger. */ 846d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan mtu = MTU_MAX; 847d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 848d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan sz = htons((uint16_t)mtu); 849d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan memcpy(p, &sz, 2); 850d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p += 2; 851d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 852d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 853d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifo->userclass[0]) { 854d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *p++ = DHO_USERCLASS; 855d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan memcpy(p, ifo->userclass, 856d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan (size_t)ifo->userclass[0] + 1); 857d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p += ifo->userclass[0] + 1; 858d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 859d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 860d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifo->vendorclassid[0]) { 861d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *p++ = DHO_VENDORCLASSID; 862d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan memcpy(p, ifo->vendorclassid, 863d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan (size_t)ifo->vendorclassid[0] + 1); 864d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p += ifo->vendorclassid[0] + 1; 865d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 866d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 867d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (type != DHCP_INFORM) { 868d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifo->leasetime != 0) { 869d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *p++ = DHO_LEASETIME; 870d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *p++ = 4; 871d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ul = htonl(ifo->leasetime); 872d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan memcpy(p, &ul, 4); 873d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p += 4; 874d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 875d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 876d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 877d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifo->hostname[0] == '\0') 878d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan hostname = get_hostname(hbuf, sizeof(hbuf), 879d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifo->options & DHCPCD_HOSTNAME_SHORT ? 1 : 0); 880d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan else 881d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan hostname = ifo->hostname; 882d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 883d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* 884d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * RFC4702 3.1 States that if we send the Client FQDN option 885d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * then we MUST NOT also send the Host Name option. 886d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * Technically we could, but that is not RFC conformant and 887d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * also seems to break some DHCP server implemetations such as 888d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * Windows. On the other hand, ISC dhcpd is just as non RFC 889d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * conformant by not accepting a partially qualified FQDN. 890d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan */ 891d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifo->fqdn != FQDN_DISABLE) { 892d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* IETF DHC-FQDN option (81), RFC4702 */ 893d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *p++ = DHO_FQDN; 894d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan lp = p; 895d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *p++ = 3; 896d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* 897d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * Flags: 0000NEOS 898d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * S: 1 => Client requests Server to update 899d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * a RR in DNS as well as PTR 900d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * O: 1 => Server indicates to client that 901d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * DNS has been updated 902d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * E: 1 => Name data is DNS format 903d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * N: 1 => Client requests Server to not 904d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * update DNS 905d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan */ 906d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (hostname) 907d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *p++ = (uint8_t)((ifo->fqdn & 0x09) | 0x04); 908d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan else 909d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *p++ = (FQDN_NONE & 0x09) | 0x04; 910d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *p++ = 0; /* from server for PTR RR */ 911d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *p++ = 0; /* from server for A RR if S=1 */ 912d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (hostname) { 913d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan i = encode_rfc1035(hostname, p); 914d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *lp = (uint8_t)(*lp + i); 915d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p += i; 916d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 917d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } else if (ifo->options & DHCPCD_HOSTNAME && hostname) { 918d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *p++ = DHO_HOSTNAME; 919d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan len = strlen(hostname); 920d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *p++ = (uint8_t)len; 921d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan memcpy(p, hostname, len); 922d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p += len; 923d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 924d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 925d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* vendor is already encoded correctly, so just add it */ 926d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifo->vendor[0]) { 927d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *p++ = DHO_VENDOR; 928d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan memcpy(p, ifo->vendor, (size_t)ifo->vendor[0] + 1); 929d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p += ifo->vendor[0] + 1; 930d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 931d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 932d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if ((ifo->auth.options & DHCPCD_AUTH_SENDREQUIRE) != 933d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan DHCPCD_AUTH_SENDREQUIRE) 934d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { 935d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* We support HMAC-MD5 */ 936d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *p++ = DHO_FORCERENEW_NONCE; 937d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *p++ = 1; 938d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *p++ = AUTH_ALG_HMAC_MD5; 939d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 940d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 941d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifo->vivco_len) { 942d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *p++ = DHO_VIVCO; 943d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan lp = p++; 944d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *lp = sizeof(ul); 945d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ul = htonl(ifo->vivco_en); 946d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan memcpy(p, &ul, sizeof(ul)); 947d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p += sizeof(ul); 948d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan for (i = 0, vivco = ifo->vivco; 949d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan i < ifo->vivco_len; 950d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan i++, vivco++) 951d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { 952d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan len = (size_t)(p - m) + vivco->len + 1; 953d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (len > sizeof(*dhcp)) 954d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan goto toobig; 955d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (vivco->len + 2 + *lp > 255) { 956d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_ERR, 957d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%s: VIVCO option too big", 958d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->name); 959d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan free(dhcp); 960d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return -1; 961d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 962d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *p++ = (uint8_t)vivco->len; 963d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan memcpy(p, vivco->data, vivco->len); 964d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p += vivco->len; 965d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *lp = (uint8_t)(*lp + vivco->len + 1); 966d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 967d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 968d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 969d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan len = (size_t)((p - m) + 3); 970d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (len > sizeof(*dhcp)) 971d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan goto toobig; 972d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *p++ = DHO_PARAMETERREQUESTLIST; 973d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan n_params = p; 974d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *p++ = 0; 975d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan for (i = 0, opt = ifp->ctx->dhcp_opts; 976d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan i < ifp->ctx->dhcp_opts_len; 977d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan i++, opt++) 978d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { 979d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (!(opt->type & REQUEST || 980d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan has_option_mask(ifo->requestmask, opt->option))) 981d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan continue; 982d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (opt->type & NOREQ) 983d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan continue; 984d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (type == DHCP_INFORM && 985d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan (opt->option == DHO_RENEWALTIME || 986d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan opt->option == DHO_REBINDTIME)) 987d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan continue; 988d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan len = (size_t)((p - m) + 2); 989d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (len > sizeof(*dhcp)) 990d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan goto toobig; 991d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *p++ = (uint8_t)opt->option; 992d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 993d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan for (i = 0, opt = ifo->dhcp_override; 994d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan i < ifo->dhcp_override_len; 995d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan i++, opt++) 996d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { 997d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* Check if added above */ 998d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan for (lp = n_params + 1; lp < p; lp++) 999d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (*lp == (uint8_t)opt->option) 1000d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan break; 1001d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (lp < p) 1002d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan continue; 1003d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (!(opt->type & REQUEST || 1004d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan has_option_mask(ifo->requestmask, opt->option))) 1005d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan continue; 1006d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (opt->type & NOREQ) 1007d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan continue; 1008d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (type == DHCP_INFORM && 1009d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan (opt->option == DHO_RENEWALTIME || 1010d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan opt->option == DHO_REBINDTIME)) 1011d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan continue; 1012d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan len = (size_t)((p - m) + 2); 1013d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (len > sizeof(*dhcp)) 1014d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan goto toobig; 1015d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *p++ = (uint8_t)opt->option; 1016d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 1017d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *n_params = (uint8_t)(p - n_params - 1); 1018d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 1019d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1020d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* silence GCC */ 1021d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan auth_len = 0; 1022d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan auth = NULL; 1023d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1024d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifo->auth.options & DHCPCD_AUTH_SEND) { 1025d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ssize_t alen = dhcp_auth_encode(&ifo->auth, 1026d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->auth.token, 1027d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan NULL, 0, 4, type, NULL, 0); 1028d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (alen != -1 && alen > UINT8_MAX) { 1029d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan errno = ERANGE; 1030d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan alen = -1; 1031d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 1032d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (alen == -1) 1033d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_ERR, 1034d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%s: dhcp_auth_encode: %m", ifp->name); 1035d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan else if (alen != 0) { 1036d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan auth_len = (uint8_t)alen; 1037d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan len = (size_t)((p + alen) - m); 1038d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (len > sizeof(*dhcp)) 1039d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan goto toobig; 1040d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *p++ = DHO_AUTHENTICATION; 1041d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *p++ = auth_len; 1042d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan auth = p; 1043d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p += auth_len; 1044d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 1045d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 1046d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1047d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *p++ = DHO_END; 1048d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1049d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* Pad out to the BOOTP minimum message length. 1050d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * Some DHCP servers incorrectly require this. */ 1051d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan while (p - m < BOOTP_MESSAGE_LENTH_MIN) 1052d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *p++ = DHO_PAD; 1053d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1054d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan len = (size_t)(p - m); 1055d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifo->auth.options & DHCPCD_AUTH_SEND && auth_len != 0) 1056d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_auth_encode(&ifo->auth, state->auth.token, 1057d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan m, len, 4, type, auth, auth_len); 1058d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1059d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *message = dhcp; 1060d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return (ssize_t)len; 1061d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1062d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tantoobig: 1063d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_ERR, "%s: DHCP messge too big", ifp->name); 1064d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan free(dhcp); 1065d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return -1; 1066d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 1067d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1068d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic ssize_t 1069d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanwrite_lease(const struct interface *ifp, const struct dhcp_message *dhcp) 1070d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 1071d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan int fd; 1072d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan size_t len; 1073d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ssize_t bytes; 1074d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan const uint8_t *e, *p; 1075d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan uint8_t l; 1076d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan uint8_t o = 0; 1077d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan const struct dhcp_state *state = D_CSTATE(ifp); 1078f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan uint8_t write_buffer[sizeof(*dhcp) + sizeof(state->server_info) + 1]; 1079f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan uint8_t *w; 1080d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1081d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* We don't write BOOTP leases */ 1082d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (IS_BOOTP(ifp, dhcp)) { 1083d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan unlink(state->leasefile); 1084d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return 0; 1085d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 1086d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1087d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_DEBUG, "%s: writing lease `%s'", 1088d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->name, state->leasefile); 1089d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1090dd90b01b5502dc66e00ea6a4d00ebdf77ea1eddcSamuel Tan fd = open(state->leasefile, O_WRONLY | O_CREAT | O_TRUNC, 0600); 1091d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (fd == -1) 1092d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return -1; 1093d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1094d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* Only write as much as we need */ 1095d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p = dhcp->options; 1096d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan e = p + sizeof(dhcp->options); 1097d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan len = sizeof(*dhcp); 1098d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan while (p < e) { 1099d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan o = *p; 1100d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (o == DHO_END) { 1101d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan len = (size_t)(p - (const uint8_t *)dhcp); 1102d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan break; 1103d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 1104d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p++; 1105d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (o != DHO_PAD) { 1106d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan l = *p++; 1107d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p += l; 1108d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 1109d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 1110f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan 1111f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan memcpy(write_buffer, dhcp, len); 1112f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan w = write_buffer + len; 1113f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan 1114f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan /* Copy in server info if this is available. */ 1115f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan if (state->server_info.gw_hwlen != 0) { 1116f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan *w++ = DHO_END; 1117f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan memcpy(w, &state->server_info, sizeof(state->server_info)); 1118f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan len += sizeof(state->server_info) + 1; 1119f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan } 1120f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan 1121f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan bytes = write(fd, write_buffer, len); 1122d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan close(fd); 1123d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return bytes; 1124d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 1125d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1126d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic struct dhcp_message * 1127d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanread_lease(struct interface *ifp) 1128d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 1129d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan int fd; 1130d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct dhcp_message *dhcp; 1131d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct dhcp_state *state = D_STATE(ifp); 1132f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan uint8_t read_buffer[sizeof(*dhcp) + sizeof(state->server_info) + 1]; 1133f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan const uint8_t *options_startp = 1134f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan read_buffer + offsetof(struct dhcp_message, options); 1135f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan const uint8_t *options_endp = options_startp + sizeof(dhcp->options); 1136f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan uint8_t option_len; 1137f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan uint8_t option_type = 0; 1138d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ssize_t bytes; 1139d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan const uint8_t *auth; 1140d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan uint8_t type; 1141d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan size_t auth_len; 1142d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1143f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan memset(&state->server_info, 0, sizeof(state->server_info)); 1144d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan fd = open(state->leasefile, O_RDONLY); 1145d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (fd == -1) { 1146d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (errno != ENOENT) 1147d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_ERR, "%s: open `%s': %m", 1148d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->name, state->leasefile); 1149d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return NULL; 1150d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 1151d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_DEBUG, "%s: reading lease `%s'", 1152d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->name, state->leasefile); 1153f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan bytes = read(fd, read_buffer, sizeof(read_buffer)); 1154f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan close(fd); 1155f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan 1156f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan /* Lease file should at minimum contain all fields before options. */ 1157f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan if (read_buffer + bytes < options_startp) 1158f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan return NULL; 1159f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan 1160d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp = calloc(1, sizeof(*dhcp)); 1161d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (dhcp == NULL) { 1162d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return NULL; 1163d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 1164f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan 1165f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan if (options_endp > read_buffer + bytes) 1166f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan options_endp = read_buffer + bytes; 1167f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan 1168f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan while (options_startp < options_endp) { 1169f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan option_type = *options_startp++; 1170f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan if (option_type == DHO_END) 1171f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan break; 1172f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan if (option_type != DHO_PAD) { 1173f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan option_len = *options_startp++; 1174f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan options_startp += option_len; 1175f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan } 1176d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 1177f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan memcpy(dhcp, read_buffer, options_startp - read_buffer); 1178d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1179d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* We may have found a BOOTP server */ 1180d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (get_option_uint8(ifp->ctx, &type, dhcp, DHO_MESSAGETYPE) == -1) 1181d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan type = 0; 1182d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1183d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* Authenticate the message */ 1184d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan auth = get_option(ifp->ctx, dhcp, DHO_AUTHENTICATION, &auth_len); 1185d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (auth) { 1186d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (dhcp_auth_validate(&state->auth, &ifp->options->auth, 1187d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan (uint8_t *)dhcp, sizeof(*dhcp), 4, type, 1188d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan auth, auth_len) == NULL) 1189d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { 1190d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_DEBUG, 1191d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%s: dhcp_auth_validate: %m", ifp->name); 1192d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan free(dhcp); 1193d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return NULL; 1194d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 1195d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state->auth.token) 1196d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_DEBUG, 1197d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%s: validated using 0x%08" PRIu32, 1198d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->name, state->auth.token->secretid); 1199d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan else 1200d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_DEBUG, 1201d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%s: accepted reconfigure key", ifp->name); 1202d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 1203d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1204f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan /* 1205f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan * DHCP server information is stored after the DHO_END character 1206f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan * in the lease file. The first byte of the server information 1207f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan * is the length of the gateway hardware address. 1208f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan */ 1209f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan options_endp = read_buffer + bytes; 1210f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan if (options_startp >= options_endp || 1211f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan options_startp + sizeof(state->server_info) > options_endp) 1212f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan return dhcp; 1213f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan 1214f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan logger(ifp->ctx, LOG_DEBUG, "%s: found server info in lease '%s'", 1215f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan ifp->name, state->leasefile); 1216f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan 1217f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan memcpy(&state->server_info, options_startp, sizeof(state->server_info)); 1218f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan if (state->server_info.gw_hwlen != ifp->hwlen) { 1219f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan logger(ifp->ctx, LOG_ERR, "%s: lease file %s has incompatible" 1220f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan "MAC address length %d (expected %zd)", 1221f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan ifp->name, state->leasefile, 1222f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan state->server_info.gw_hwlen, ifp->hwlen); 1223f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan memset(&state->server_info, 0, sizeof(state->server_info)); 1224f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan } 1225d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return dhcp; 1226d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 1227d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1228d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic const struct dhcp_opt * 1229d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_getoverride(const struct if_options *ifo, unsigned int o) 1230d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 1231d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan size_t i; 1232d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan const struct dhcp_opt *opt; 1233d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1234d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan for (i = 0, opt = ifo->dhcp_override; 1235d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan i < ifo->dhcp_override_len; 1236d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan i++, opt++) 1237d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { 1238d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (opt->option == o) 1239d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return opt; 1240d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 1241d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return NULL; 1242d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 1243d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1244d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic const uint8_t * 1245d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_getoption(struct dhcpcd_ctx *ctx, 1246d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan size_t *os, unsigned int *code, size_t *len, 1247d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan const uint8_t *od, size_t ol, struct dhcp_opt **oopt) 1248d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 1249d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan size_t i; 1250d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct dhcp_opt *opt; 1251d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1252d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (od) { 1253d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ol < 2) { 1254d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan errno = EINVAL; 1255d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return NULL; 1256d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 1257d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *os = 2; /* code + len */ 1258d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *code = (unsigned int)*od++; 1259d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *len = (size_t)*od++; 1260d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (*len > ol) { 1261d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan errno = EINVAL; 1262d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return NULL; 1263d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 1264d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 1265d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1266d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan for (i = 0, opt = ctx->dhcp_opts; i < ctx->dhcp_opts_len; i++, opt++) { 1267d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (opt->option == *code) { 1268d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *oopt = opt; 1269d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan break; 1270d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 1271d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 1272d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1273d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return od; 1274d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 1275d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1276d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanssize_t 1277d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_env(char **env, const char *prefix, const struct dhcp_message *dhcp, 1278d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan const struct interface *ifp) 1279d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 1280d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan const struct if_options *ifo; 1281d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan const uint8_t *p; 1282d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct in_addr addr; 1283d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct in_addr net; 1284d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct in_addr brd; 1285d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct dhcp_opt *opt, *vo; 1286d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan size_t e, i, pl; 1287d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan char **ep; 1288d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan char cidr[4], safe[(BOOTFILE_LEN * 4) + 1]; 1289d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan uint8_t overl = 0; 1290d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan uint32_t en; 1291d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1292d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan e = 0; 1293d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifo = ifp->options; 1294d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan get_option_uint8(ifp->ctx, &overl, dhcp, DHO_OPTIONSOVERLOADED); 1295d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1296d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (env == NULL) { 1297d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (dhcp->yiaddr || dhcp->ciaddr) 1298d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan e += 5; 1299d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (*dhcp->bootfile && !(overl & 1)) 1300d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan e++; 1301d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (*dhcp->servername && !(overl & 2)) 1302d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan e++; 1303d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan for (i = 0, opt = ifp->ctx->dhcp_opts; 1304d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan i < ifp->ctx->dhcp_opts_len; 1305d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan i++, opt++) 1306d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { 1307d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (has_option_mask(ifo->nomask, opt->option)) 1308d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan continue; 1309d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (dhcp_getoverride(ifo, opt->option)) 1310d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan continue; 1311d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p = get_option(ifp->ctx, dhcp, opt->option, &pl); 1312d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (!p) 1313d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan continue; 1314d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan e += dhcp_envoption(ifp->ctx, NULL, NULL, ifp->name, 1315d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan opt, dhcp_getoption, p, pl); 1316d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 1317d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan for (i = 0, opt = ifo->dhcp_override; 1318d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan i < ifo->dhcp_override_len; 1319d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan i++, opt++) 1320d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { 1321d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (has_option_mask(ifo->nomask, opt->option)) 1322d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan continue; 1323d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p = get_option(ifp->ctx, dhcp, opt->option, &pl); 1324d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (!p) 1325d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan continue; 1326d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan e += dhcp_envoption(ifp->ctx, NULL, NULL, ifp->name, 1327d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan opt, dhcp_getoption, p, pl); 1328d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 1329d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return (ssize_t)e; 1330d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 1331d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1332d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ep = env; 1333d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (dhcp->yiaddr || dhcp->ciaddr) { 1334d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* Set some useful variables that we derive from the DHCP 1335d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * message but are not necessarily in the options */ 1336d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan addr.s_addr = dhcp->yiaddr ? dhcp->yiaddr : dhcp->ciaddr; 1337d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan setvar(ifp->ctx, &ep, prefix, "ip_address", inet_ntoa(addr)); 1338d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (get_option_addr(ifp->ctx, &net, 1339d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp, DHO_SUBNETMASK) == -1) { 1340d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan net.s_addr = ipv4_getnetmask(addr.s_addr); 1341d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan setvar(ifp->ctx, &ep, prefix, 1342d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "subnet_mask", inet_ntoa(net)); 1343d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 1344d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan snprintf(cidr, sizeof(cidr), "%d", inet_ntocidr(net)); 1345d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan setvar(ifp->ctx, &ep, prefix, "subnet_cidr", cidr); 1346d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (get_option_addr(ifp->ctx, &brd, 1347d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp, DHO_BROADCAST) == -1) { 1348d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan brd.s_addr = addr.s_addr | ~net.s_addr; 1349d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan setvar(ifp->ctx, &ep, prefix, 1350d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "broadcast_address", inet_ntoa(brd)); 1351d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 1352d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan addr.s_addr = dhcp->yiaddr & net.s_addr; 1353d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan setvar(ifp->ctx, &ep, prefix, 1354d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "network_number", inet_ntoa(addr)); 1355d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 1356d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1357d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (*dhcp->bootfile && !(overl & 1)) { 1358d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan print_string(safe, sizeof(safe), STRING, 1359d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp->bootfile, sizeof(dhcp->bootfile)); 1360d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan setvar(ifp->ctx, &ep, prefix, "filename", safe); 1361d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 1362d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (*dhcp->servername && !(overl & 2)) { 1363d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan print_string(safe, sizeof(safe), STRING | DOMAIN, 1364d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp->servername, sizeof(dhcp->servername)); 1365d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan setvar(ifp->ctx, &ep, prefix, "server_name", safe); 1366d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 1367d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1368d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* Zero our indexes */ 1369d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (env) { 1370d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan for (i = 0, opt = ifp->ctx->dhcp_opts; 1371d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan i < ifp->ctx->dhcp_opts_len; 1372d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan i++, opt++) 1373d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_zero_index(opt); 1374d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan for (i = 0, opt = ifp->options->dhcp_override; 1375d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan i < ifp->options->dhcp_override_len; 1376d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan i++, opt++) 1377d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_zero_index(opt); 1378d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan for (i = 0, opt = ifp->ctx->vivso; 1379d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan i < ifp->ctx->vivso_len; 1380d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan i++, opt++) 1381d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_zero_index(opt); 1382d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 1383d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1384d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan for (i = 0, opt = ifp->ctx->dhcp_opts; 1385d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan i < ifp->ctx->dhcp_opts_len; 1386d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan i++, opt++) 1387d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { 1388d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (has_option_mask(ifo->nomask, opt->option)) 1389d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan continue; 1390d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (dhcp_getoverride(ifo, opt->option)) 1391d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan continue; 1392d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if ((p = get_option(ifp->ctx, dhcp, opt->option, &pl))) { 1393d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ep += dhcp_envoption(ifp->ctx, ep, prefix, ifp->name, 1394d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan opt, dhcp_getoption, p, pl); 1395d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (opt->option == DHO_VIVSO && 1396d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan pl > (int)sizeof(uint32_t)) 1397d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { 1398d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan memcpy(&en, p, sizeof(en)); 1399d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan en = ntohl(en); 1400d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan vo = vivso_find(en, ifp); 1401d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (vo) { 1402d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* Skip over en + total size */ 1403d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p += sizeof(en) + 1; 1404d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan pl -= sizeof(en) + 1; 1405d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ep += dhcp_envoption(ifp->ctx, 1406d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ep, prefix, ifp->name, 1407d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan vo, dhcp_getoption, p, pl); 1408d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 1409d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 1410d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 1411d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 1412d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1413d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan for (i = 0, opt = ifo->dhcp_override; 1414d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan i < ifo->dhcp_override_len; 1415d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan i++, opt++) 1416d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { 1417d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (has_option_mask(ifo->nomask, opt->option)) 1418d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan continue; 1419d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if ((p = get_option(ifp->ctx, dhcp, opt->option, &pl))) 1420d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ep += dhcp_envoption(ifp->ctx, ep, prefix, ifp->name, 1421d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan opt, dhcp_getoption, p, pl); 1422d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 1423d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1424d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return ep - env; 1425d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 1426d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1427d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void 1428d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanget_lease(struct dhcpcd_ctx *ctx, 1429d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct dhcp_lease *lease, const struct dhcp_message *dhcp) 1430d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 1431d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1432d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan lease->cookie = dhcp->cookie; 1433d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* BOOTP does not set yiaddr for replies when ciaddr is set. */ 1434d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (dhcp->yiaddr) 1435d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan lease->addr.s_addr = dhcp->yiaddr; 1436d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan else 1437d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan lease->addr.s_addr = dhcp->ciaddr; 1438d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (get_option_addr(ctx, &lease->net, dhcp, DHO_SUBNETMASK) == -1) 1439d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan lease->net.s_addr = ipv4_getnetmask(lease->addr.s_addr); 1440d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (get_option_addr(ctx, &lease->brd, dhcp, DHO_BROADCAST) == -1) 1441d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan lease->brd.s_addr = lease->addr.s_addr | ~lease->net.s_addr; 1442d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (get_option_uint32(ctx, &lease->leasetime, dhcp, DHO_LEASETIME) != 0) 1443d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan lease->leasetime = ~0U; /* Default to infinite lease */ 1444d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (get_option_uint32(ctx, &lease->renewaltime, 1445d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp, DHO_RENEWALTIME) != 0) 1446d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan lease->renewaltime = 0; 1447d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (get_option_uint32(ctx, &lease->rebindtime, 1448d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp, DHO_REBINDTIME) != 0) 1449d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan lease->rebindtime = 0; 1450d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (get_option_addr(ctx, &lease->server, dhcp, DHO_SERVERID) != 0) 1451d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan lease->server.s_addr = INADDR_ANY; 1452d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 1453d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1454d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic const char * 1455d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanget_dhcp_op(uint8_t type) 1456d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 1457d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan const struct dhcp_op *d; 1458d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1459d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan for (d = dhcp_ops; d->name; d++) 1460d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (d->value == type) 1461d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return d->name; 1462d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return NULL; 1463d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 1464d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1465d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void 1466d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_fallback(void *arg) 1467d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 1468d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct interface *iface; 1469d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1470d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan iface = (struct interface *)arg; 1471d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcpcd_selectprofile(iface, iface->options->fallback); 1472d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcpcd_startinterface(iface); 1473d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 1474d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1475d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanuint32_t 1476d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_xid(const struct interface *ifp) 1477d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 1478d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan uint32_t xid; 1479d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1480d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifp->options->options & DHCPCD_XID_HWADDR && 1481d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->hwlen >= sizeof(xid)) 1482d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* The lower bits are probably more unique on the network */ 1483d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan memcpy(&xid, (ifp->hwaddr + ifp->hwlen) - sizeof(xid), 1484d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan sizeof(xid)); 1485d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan else 1486d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan xid = arc4random(); 1487d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1488d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return xid; 1489d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 1490d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1491d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanvoid 1492d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_close(struct interface *ifp) 1493d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 1494d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct dhcp_state *state = D_STATE(ifp); 1495d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1496d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state == NULL) 1497d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 1498d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1499d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state->raw_fd != -1) { 1500d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan eloop_event_delete(ifp->ctx->eloop, state->raw_fd, 0); 1501d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan close(state->raw_fd); 1502d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->raw_fd = -1; 1503d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 1504d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1505d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->interval = 0; 1506d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 1507d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1508d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int 1509d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_openudp(struct interface *ifp) 1510d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 1511d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan int s; 1512d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct sockaddr_in sin; 1513d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan int n; 1514d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct dhcp_state *state; 1515d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef SO_BINDTODEVICE 1516d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct ifreq ifr; 1517d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan char *p; 1518d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif 1519d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1520d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef SOCK_CLOEXEC 1521d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if ((s = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP)) == -1) 1522d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return -1; 1523d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#else 1524d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if ((s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) 1525d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return -1; 1526d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if ((n = fcntl(s, F_GETFD, 0)) == -1 || 1527d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan fcntl(s, F_SETFD, n | FD_CLOEXEC) == -1) 1528d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { 1529d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan close(s); 1530d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return -1; 1531d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 1532d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif 1533d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1534d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan n = 1; 1535d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)) == -1) 1536d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan goto eexit; 1537d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef SO_BINDTODEVICE 1538d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifp) { 1539d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan memset(&ifr, 0, sizeof(ifr)); 1540d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name)); 1541d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* We can only bind to the real device */ 1542d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p = strchr(ifr.ifr_name, ':'); 1543d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (p) 1544d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *p = '\0'; 1545d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, &ifr, 1546d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan sizeof(ifr)) == -1) 1547d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan goto eexit; 1548d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 1549d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif 1550d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan memset(&sin, 0, sizeof(sin)); 1551d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan sin.sin_family = AF_INET; 1552d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan sin.sin_port = htons(DHCP_CLIENT_PORT); 1553d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifp) { 1554d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state = D_STATE(ifp); 1555d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan sin.sin_addr.s_addr = state->addr.s_addr; 1556d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } else 1557d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state = NULL; /* appease gcc */ 1558d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) == -1) 1559d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan goto eexit; 1560d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1561d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return s; 1562d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1563d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Taneexit: 1564d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan close(s); 1565d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return -1; 1566d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 1567d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1568d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic uint16_t 1569d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanchecksum(const void *data, unsigned int len) 1570d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 1571d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan const uint8_t *addr = data; 1572d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan uint32_t sum = 0; 1573d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1574d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan while (len > 1) { 1575d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan sum += (uint32_t)(addr[0] * 256 + addr[1]); 1576d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan addr += 2; 1577d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan len -= 2; 1578d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 1579d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1580d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (len == 1) 1581d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan sum += (uint32_t)(*addr * 256); 1582d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1583d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan sum = (sum >> 16) + (sum & 0xffff); 1584d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan sum += (sum >> 16); 1585d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1586d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return (uint16_t)~htons((uint16_t)sum); 1587d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 1588d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1589d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic struct udp_dhcp_packet * 1590d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_makeudppacket(size_t *sz, const uint8_t *data, size_t length, 1591d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct in_addr source, struct in_addr dest) 1592d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 1593d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct udp_dhcp_packet *udpp; 1594d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct ip *ip; 1595d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct udphdr *udp; 1596d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1597d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan udpp = calloc(1, sizeof(*udpp)); 1598d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (udpp == NULL) 1599d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return NULL; 1600d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ip = &udpp->ip; 1601d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan udp = &udpp->udp; 1602d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1603d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* OK, this is important :) 1604d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * We copy the data to our packet and then create a small part of the 1605d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * ip structure and an invalid ip_len (basically udp length). 1606d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * We then fill the udp structure and put the checksum 1607d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * of the whole packet into the udp checksum. 1608d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * Finally we complete the ip structure and ip checksum. 1609d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * If we don't do the ordering like so then the udp checksum will be 1610d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * broken, so find another way of doing it! */ 1611d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1612d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan memcpy(&udpp->dhcp, data, length); 1613d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1614d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ip->ip_p = IPPROTO_UDP; 1615d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ip->ip_src.s_addr = source.s_addr; 1616d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (dest.s_addr == 0) 1617d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ip->ip_dst.s_addr = INADDR_BROADCAST; 1618d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan else 1619d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ip->ip_dst.s_addr = dest.s_addr; 1620d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1621d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan udp->uh_sport = htons(DHCP_CLIENT_PORT); 1622d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan udp->uh_dport = htons(DHCP_SERVER_PORT); 1623d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan udp->uh_ulen = htons((uint16_t)(sizeof(*udp) + length)); 1624d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ip->ip_len = udp->uh_ulen; 1625d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan udp->uh_sum = checksum(udpp, sizeof(*udpp)); 1626d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1627d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ip->ip_v = IPVERSION; 1628d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ip->ip_hl = sizeof(*ip) >> 2; 1629d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ip->ip_id = (uint16_t)arc4random_uniform(UINT16_MAX); 1630d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ip->ip_ttl = IPDEFTTL; 1631d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ip->ip_len = htons((uint16_t)(sizeof(*ip) + sizeof(*udp) + length)); 1632d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ip->ip_sum = checksum(ip, sizeof(*ip)); 1633d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1634d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *sz = sizeof(*ip) + sizeof(*udp) + length; 1635d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return udpp; 1636d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 1637d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1638d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void 1639d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tansend_message(struct interface *ifp, uint8_t type, 1640d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan void (*callback)(void *)) 1641d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 1642d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct dhcp_state *state = D_STATE(ifp); 1643d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct if_options *ifo = ifp->options; 1644d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct dhcp_message *dhcp; 1645d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct udp_dhcp_packet *udp; 1646d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan size_t len; 1647d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ssize_t r; 1648d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct in_addr from, to; 1649d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan in_addr_t a = INADDR_ANY; 1650d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct timespec tv; 1651d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan int s; 1652d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef IN_IFF_NOTUSEABLE 1653d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct ipv4_addr *ia; 1654d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif 1655d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1656d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (!callback) 1657d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_DEBUG, "%s: sending %s with xid 0x%x", 1658d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->name, 1659d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifo->options & DHCPCD_BOOTP ? "BOOTP" : get_dhcp_op(type), 1660d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->xid); 1661d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan else { 1662d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state->interval == 0) 1663d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->interval = 4; 1664d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan else { 1665d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->interval *= 2; 1666d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state->interval > 64) 1667d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->interval = 64; 1668d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 1669d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan tv.tv_sec = state->interval + DHCP_RAND_MIN; 1670d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan tv.tv_nsec = (suseconds_t)arc4random_uniform( 1671d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan (DHCP_RAND_MAX - DHCP_RAND_MIN) * NSEC_PER_SEC); 1672d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan timespecnorm(&tv); 1673d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_DEBUG, 1674d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%s: sending %s (xid 0x%x), next in %0.1f seconds", 1675d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->name, 1676d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifo->options & DHCPCD_BOOTP ? "BOOTP" : get_dhcp_op(type), 1677d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->xid, 1678d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan timespec_to_double(&tv)); 1679d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 1680d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1681d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (dhcp_open(ifp) == -1) 1682d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 1683d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1684d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state->added && !(state->added & STATE_FAKE) && 1685d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->addr.s_addr != INADDR_ANY && 1686d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->new != NULL && 1687d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef IN_IFF_NOTUSEABLE 1688d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ((ia = ipv4_iffindaddr(ifp, &state->addr, NULL)) && 1689d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan !(ia->addr_flags & IN_IFF_NOTUSEABLE)) && 1690d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif 1691d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan (state->new->cookie == htonl(MAGIC_COOKIE) || 1692d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->options->options & DHCPCD_INFORM)) 1693d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { 1694d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan s = dhcp_openudp(ifp); 1695d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (s == -1 && errno != EADDRINUSE) 1696d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_ERR, 1697d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%s: dhcp_openudp: %m", ifp->name); 1698d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } else 1699d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan s = -1; 1700d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1701d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* If we couldn't open a UDP port for our IP address 1702d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * then we cannot renew. 1703d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * This could happen if our IP was pulled out from underneath us. 1704d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * Also, we should not unicast from a BOOTP lease. */ 1705d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (s == -1 || 1706d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan (!(ifo->options & DHCPCD_INFORM) && 1707d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan IS_BOOTP(ifp, state->new))) 1708d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { 1709d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan a = state->addr.s_addr; 1710d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->addr.s_addr = INADDR_ANY; 1711d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 1712d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan r = make_message(&dhcp, ifp, type); 1713d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (r == -1) 1714d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan goto fail; 1715d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan len = (size_t)r; 1716d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (a) 1717d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->addr.s_addr = a; 1718d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan from.s_addr = dhcp->ciaddr; 1719d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (from.s_addr) 1720d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan to.s_addr = state->lease.server.s_addr; 1721d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan else 1722d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan to.s_addr = INADDR_ANY; 1723d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (to.s_addr && to.s_addr != INADDR_BROADCAST) { 1724d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct sockaddr_in sin; 1725d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1726d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan memset(&sin, 0, sizeof(sin)); 1727d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan sin.sin_family = AF_INET; 1728d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan sin.sin_addr.s_addr = to.s_addr; 1729d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan sin.sin_port = htons(DHCP_SERVER_PORT); 1730d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan r = sendto(s, (uint8_t *)dhcp, len, 0, 1731d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan (struct sockaddr *)&sin, sizeof(sin)); 1732d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (r == -1) 1733d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_ERR, 1734d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%s: dhcp_sendpacket: %m", ifp->name); 1735d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } else { 1736d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan size_t ulen; 1737d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1738d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan r = 0; 1739d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan udp = dhcp_makeudppacket(&ulen, (uint8_t *)dhcp, len, from, to); 1740d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (udp == NULL) { 1741d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_ERR, "dhcp_makeudppacket: %m"); 1742d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } else { 1743d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan r = if_sendrawpacket(ifp, ETHERTYPE_IP, 1744f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan (uint8_t *)udp, ulen, NULL); 1745d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan free(udp); 1746d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 1747d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* If we failed to send a raw packet this normally means 1748d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * we don't have the ability to work beneath the IP layer 1749d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * for this interface. 1750d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * As such we remove it from consideration without actually 1751d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * stopping the interface. */ 1752d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (r == -1) { 1753d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_ERR, 1754d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%s: if_sendrawpacket: %m", ifp->name); 1755d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan switch(errno) { 1756d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan case ENETDOWN: 1757d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan case ENETRESET: 1758d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan case ENETUNREACH: 1759d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan break; 1760d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan default: 1761d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (!(ifp->ctx->options & DHCPCD_TEST)) 1762d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_drop(ifp, "FAIL"); 1763d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_free(ifp); 1764d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan eloop_timeout_delete(ifp->ctx->eloop, 1765d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan NULL, ifp); 1766d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan callback = NULL; 1767d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 1768d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 1769d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 1770d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan free(dhcp); 1771d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1772d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanfail: 1773d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (s != -1) 1774d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan close(s); 1775d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1776d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* Even if we fail to send a packet we should continue as we are 1777d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * as our failure timeouts will change out codepath when needed. */ 1778d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (callback) 1779d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan eloop_timeout_add_tv(ifp->ctx->eloop, &tv, callback, ifp); 1780d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 1781d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1782d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void 1783d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tansend_inform(void *arg) 1784d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 1785d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1786d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan send_message((struct interface *)arg, DHCP_INFORM, send_inform); 1787d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 1788d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1789d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void 1790d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tansend_discover(void *arg) 1791d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 1792d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1793d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan send_message((struct interface *)arg, DHCP_DISCOVER, send_discover); 1794d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 1795d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1796d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void 1797d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tansend_request(void *arg) 1798d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 1799d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1800d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan send_message((struct interface *)arg, DHCP_REQUEST, send_request); 1801d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 1802d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1803d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void 1804d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tansend_renew(void *arg) 1805d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 1806d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1807d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan send_message((struct interface *)arg, DHCP_REQUEST, send_renew); 1808d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 1809d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1810d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void 1811d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tansend_rebind(void *arg) 1812d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 1813d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1814d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan send_message((struct interface *)arg, DHCP_REQUEST, send_rebind); 1815d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 1816d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1817d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanvoid 1818d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_discover(void *arg) 1819d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 1820d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct interface *ifp = arg; 1821d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct dhcp_state *state = D_STATE(ifp); 1822d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct if_options *ifo = ifp->options; 1823d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 182423ff6edd8b4ec796a32d36a3eca8a8d8c785b565Samuel Tan rpc_signal_status("Discover"); 1825d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->state = DHS_DISCOVER; 1826d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->xid = dhcp_xid(ifp); 18275158c9dfe576a285663b4ba16828fd6e9b35779cSamuel Tan state->nak_receive_count = 0; 18285158c9dfe576a285663b4ba16828fd6e9b35779cSamuel Tan state->failed_address_offer_count = 0; 1829d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); 1830d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifo->fallback) 1831d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan eloop_timeout_add_sec(ifp->ctx->eloop, 1832d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifo->reboot, dhcp_fallback, ifp); 1833d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan else if (ifo->options & DHCPCD_IPV4LL && 1834d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan !IN_LINKLOCAL(htonl(state->addr.s_addr))) 1835d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan eloop_timeout_add_sec(ifp->ctx->eloop, 1836d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifo->reboot, ipv4ll_start, ifp); 1837d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifo->options & DHCPCD_REQUEST) 1838d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_INFO, 1839d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%s: soliciting a DHCP lease (requesting %s)", 1840d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->name, inet_ntoa(ifo->req_addr)); 1841d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan else 1842d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_INFO, 1843d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%s: soliciting a %s lease", 1844d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->name, ifo->options & DHCPCD_BOOTP ? "BOOTP" : "DHCP"); 1845d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan send_discover(ifp); 1846d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 1847d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1848d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void 1849d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_request(void *arg) 1850d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 1851d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct interface *ifp = arg; 1852d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct dhcp_state *state = D_STATE(ifp); 1853d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 185423ff6edd8b4ec796a32d36a3eca8a8d8c785b565Samuel Tan rpc_signal_status("Request"); 1855d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->state = DHS_REQUEST; 18565158c9dfe576a285663b4ba16828fd6e9b35779cSamuel Tan state->nak_receive_count = 0; 1857d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan send_request(ifp); 1858d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 1859d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1860d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void 1861d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_expire(void *arg) 1862d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 1863d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct interface *ifp = arg; 1864d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct dhcp_state *state = D_STATE(ifp); 1865d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1866d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_ERR, "%s: DHCP lease expired", ifp->name); 1867d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); 1868d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_drop(ifp, "EXPIRE"); 1869d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan unlink(state->leasefile); 1870d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->interval = 0; 1871d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_discover(ifp); 1872d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 1873d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1874d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void 1875d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_decline(struct interface *ifp) 1876d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 1877d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1878d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan send_message(ifp, DHCP_DECLINE, NULL); 1879d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 1880d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1881d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void 1882d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_renew(void *arg) 1883d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 1884d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct interface *ifp = arg; 1885d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct dhcp_state *state = D_STATE(ifp); 1886d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct dhcp_lease *lease = &state->lease; 1887d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 188823ff6edd8b4ec796a32d36a3eca8a8d8c785b565Samuel Tan rpc_signal_status("Renew"); 1889d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_DEBUG, "%s: renewing lease of %s", 1890d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->name, inet_ntoa(lease->addr)); 1891d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_DEBUG, "%s: rebind in %"PRIu32" seconds," 1892d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan " expire in %"PRIu32" seconds", 1893d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->name, lease->rebindtime - lease->renewaltime, 1894d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan lease->leasetime - lease->renewaltime); 1895d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->state = DHS_RENEW; 1896d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->xid = dhcp_xid(ifp); 18975158c9dfe576a285663b4ba16828fd6e9b35779cSamuel Tan state->nak_receive_count = 0; 1898d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan send_renew(ifp); 1899d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 1900d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1901d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifndef IN_IFF_TENTATIVE 1902d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void 1903d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_arp_announced(struct arp_state *astate) 1904d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 1905d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1906d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan arp_close(astate->iface); 1907d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 1908d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif 1909d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 1910d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void 1911d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_rebind(void *arg) 1912d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 1913d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct interface *ifp = arg; 1914d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct dhcp_state *state = D_STATE(ifp); 1915d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct dhcp_lease *lease = &state->lease; 1916d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 191723ff6edd8b4ec796a32d36a3eca8a8d8c785b565Samuel Tan rpc_signal_status("Rebind"); 1918d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_WARNING, 1919d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%s: failed to renew DHCP, rebinding", ifp->name); 1920d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_DEBUG, "%s: expire in %"PRIu32" seconds", 1921d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->name, lease->leasetime - lease->rebindtime); 1922d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->state = DHS_REBIND; 1923d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan eloop_timeout_delete(ifp->ctx->eloop, send_renew, ifp); 1924d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->lease.server.s_addr = 0; 19255158c9dfe576a285663b4ba16828fd6e9b35779cSamuel Tan state->nak_receive_count = 0; 1926d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->options->options &= ~(DHCPCD_CSR_WARNED | 1927d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan DHCPCD_ROUTER_HOST_ROUTE_WARNED); 1928d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan send_rebind(ifp); 1929d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 1930d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 19319177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tanstatic void 19329177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Taninit_option_iterator(const struct dhcp_message *message, 19339177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan struct dhcp_option_iterator *iterator) 19349177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan{ 19359177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan iterator->message = message; 19369177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan iterator->ptr = message->options; 19379177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan iterator->end = iterator->ptr + sizeof(message->options); 19389177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan iterator->extra_option_locations = 0; 19399177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan iterator->extra_option_locations_set = 0; 19409177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan} 19419177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan 19429177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tanstatic int 19439177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Taniterate_next_option(struct dhcp_option_iterator *iterator, 19449177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan uint8_t *option, uint8_t *length, const uint8_t **value) 19459177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan{ 19469177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan uint8_t option_code; 19479177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan uint8_t option_len; 19489177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan 19499177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan /* Process special DHO_PAD and DHO_END opcodes. */ 19509177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan while (iterator->ptr < iterator->end) { 19519177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan if (*iterator->ptr == DHO_PAD) { 19529177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan iterator->ptr++; 19539177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan continue; 19549177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan } 19559177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan 19569177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan if (*iterator->ptr != DHO_END) 19579177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan break; 19589177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan 19599177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan if (iterator->extra_option_locations & 19609177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan OPTION_OVERLOADED_BOOT_FILE) { 19619177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan iterator->extra_option_locations &= 19629177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan ~OPTION_OVERLOADED_BOOT_FILE; 19639177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan iterator->ptr = iterator->message->bootfile; 19649177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan iterator->end = iterator->ptr + 19659177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan sizeof(iterator->message->bootfile); 19669177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan } else if (iterator->extra_option_locations & 19679177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan OPTION_OVERLOADED_SERVER_NAME) { 19689177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan iterator->extra_option_locations &= 19699177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan ~OPTION_OVERLOADED_SERVER_NAME; 19709177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan iterator->ptr = iterator->message->servername; 19719177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan iterator->end = iterator->ptr + 19729177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan sizeof(iterator->message->servername); 19739177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan } else 19749177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan return 0; 19759177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan } 19769177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan 19779177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan if (iterator->ptr + 2 > iterator->end) 19789177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan return 0; 19799177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan 19809177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan option_code = *iterator->ptr++; 19819177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan option_len = *iterator->ptr++; 19829177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan if (iterator->ptr + option_len > iterator->end) 19839177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan return 0; 19849177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan 19859177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan if (option_code == DHO_OPTIONSOVERLOADED && option_len > 0 && 19869177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan !iterator->extra_option_locations_set) { 19879177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan iterator->extra_option_locations = *iterator->ptr; 19889177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan iterator->extra_option_locations_set = 1; 19899177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan } 19909177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan 19919177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan if (option) 19929177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan *option = option_code; 19939177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan if (length) 19949177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan *length = option_len; 19959177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan if (value) 19969177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan *value = iterator->ptr; 19979177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan 19989177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan iterator->ptr += option_len; 19999177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan 20009177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan return 1; 20019177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan} 20029177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan 20039177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tanstatic void 20049177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tanmerge_option_values(const struct dhcp_message *src, 20059177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan struct dhcp_message *dst, uint8_t *copy_options) 20069177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan{ 20079177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan uint8_t supplied_options[OPTION_MASK_SIZE]; 20089177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan struct dhcp_option_iterator dst_iterator; 20099177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan struct dhcp_option_iterator src_iterator; 20109177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan uint8_t option; 20119177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan const uint8_t *option_value; 20129177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan uint8_t option_length; 20139177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan uint8_t *out; 20149177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan const uint8_t *out_end; 20159177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan int added_options = 0; 20169177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan 20179177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan /* Traverse the destination message for options already supplied. */ 20189177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan memset(&supplied_options, 0, sizeof(supplied_options)); 20199177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan init_option_iterator(dst, &dst_iterator); 20209177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan while (iterate_next_option(&dst_iterator, &option, NULL, NULL)) { 20219177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan add_option_mask(supplied_options, option); 20229177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan } 20239177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan 20249177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan /* We will start merging options at the end of the last block 20259177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan * the iterator traversed to. The const cast below is safe since 20269177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan * this points to data within the (non-const) dst message. */ 20279177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan out = (uint8_t *) dst_iterator.ptr; 20289177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan out_end = dst_iterator.end; 20299177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan 20309177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan init_option_iterator(src, &src_iterator); 20319177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan while (iterate_next_option(&src_iterator, &option, &option_length, 20329177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan &option_value)) { 20339177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan if (has_option_mask(supplied_options, option) || 20349177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan !has_option_mask(copy_options, option)) 20359177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan continue; 20369177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan /* We need space for this option, plus a trailing DHO_END. */ 20379177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan if (out + option_length + 3 > out_end) { 20389177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan syslog(LOG_ERR, 20399177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan "%s: unable to fit option %d (length %d)", 20409177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan __func__, option, option_length); 20419177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan continue; 20429177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan } 20439177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan *out++ = option; 20449177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan *out++ = option_length; 20459177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan memcpy(out, option_value, option_length); 20469177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan out += option_length; 20479177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan added_options++; 20489177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan } 20499177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan 20509177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan if (added_options) { 20519177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan *out++ = DHO_END; 20529177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan syslog(LOG_INFO, "carrying over %d options from original offer", 20539177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan added_options); 20549177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan } 20559177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan} 20569177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan 2057d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanvoid 2058d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_bind(struct interface *ifp, struct arp_state *astate) 2059d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 2060d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct dhcp_state *state = D_STATE(ifp); 2061d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct if_options *ifo = ifp->options; 2062d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct dhcp_lease *lease = &state->lease; 2063d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan uint8_t ipv4ll = 0; 2064d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 2065d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state->state == DHS_BOUND) 2066d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan goto applyaddr; 2067d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->reason = NULL; 2068d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan free(state->old); 2069d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->old = state->new; 2070d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->new = state->offer; 2071d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->offer = NULL; 2072d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan get_lease(ifp->ctx, lease, state->new); 2073d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifo->options & DHCPCD_STATIC) { 2074d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_INFO, "%s: using static address %s/%d", 2075d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->name, inet_ntoa(lease->addr), 2076d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan inet_ntocidr(lease->net)); 2077d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan lease->leasetime = ~0U; 2078d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->reason = "STATIC"; 2079d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } else if (state->new->cookie != htonl(MAGIC_COOKIE)) { 2080d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_INFO, "%s: using IPv4LL address %s", 2081d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->name, inet_ntoa(lease->addr)); 2082d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan lease->leasetime = ~0U; 2083d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->reason = "IPV4LL"; 2084d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ipv4ll = 1; 2085d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } else if (ifo->options & DHCPCD_INFORM) { 2086d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifo->req_addr.s_addr != 0) 2087d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan lease->addr.s_addr = ifo->req_addr.s_addr; 2088d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan else 2089d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan lease->addr.s_addr = state->addr.s_addr; 2090d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_INFO, "%s: received approval for %s", 2091d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->name, inet_ntoa(lease->addr)); 2092d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan lease->leasetime = ~0U; 2093d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->reason = "INFORM"; 2094d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } else { 2095d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (lease->frominfo) 2096d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->reason = "TIMEOUT"; 2097d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (lease->leasetime == ~0U) { 2098d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan lease->renewaltime = 2099d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan lease->rebindtime = 2100d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan lease->leasetime; 2101d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_INFO, "%s: leased %s for infinity", 2102d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->name, inet_ntoa(lease->addr)); 2103d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } else { 2104d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (lease->leasetime < DHCP_MIN_LEASE) { 2105d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_WARNING, 2106d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%s: minimum lease is %d seconds", 2107d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->name, DHCP_MIN_LEASE); 2108d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan lease->leasetime = DHCP_MIN_LEASE; 2109d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 2110d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (lease->rebindtime == 0) 2111d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan lease->rebindtime = 2112d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan (uint32_t)(lease->leasetime * T2); 2113d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan else if (lease->rebindtime >= lease->leasetime) { 2114d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan lease->rebindtime = 2115d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan (uint32_t)(lease->leasetime * T2); 2116d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_WARNING, 2117d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%s: rebind time greater than lease " 2118d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "time, forcing to %"PRIu32" seconds", 2119d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->name, lease->rebindtime); 2120d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 2121d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (lease->renewaltime == 0) 2122d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan lease->renewaltime = 2123d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan (uint32_t)(lease->leasetime * T1); 2124d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan else if (lease->renewaltime > lease->rebindtime) { 2125d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan lease->renewaltime = 2126d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan (uint32_t)(lease->leasetime * T1); 2127d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_WARNING, 2128d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%s: renewal time greater than rebind " 2129d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "time, forcing to %"PRIu32" seconds", 2130d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->name, lease->renewaltime); 2131d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 2132d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, 2133d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan lease->addr.s_addr == state->addr.s_addr && 2134d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan !(state->added & STATE_FAKE) ? 2135d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan LOG_DEBUG : LOG_INFO, 2136d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%s: leased %s for %"PRIu32" seconds", ifp->name, 2137d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan inet_ntoa(lease->addr), lease->leasetime); 2138d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 2139d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 2140d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifp->ctx->options & DHCPCD_TEST) { 2141d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->reason = "TEST"; 2142d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan script_runreason(ifp, state->reason); 2143d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan eloop_exit(ifp->ctx->eloop, EXIT_SUCCESS); 2144d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 2145d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 2146d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state->reason == NULL) { 2147d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state->old && !(state->added & STATE_FAKE)) { 2148d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state->old->yiaddr == state->new->yiaddr && 2149d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan lease->server.s_addr) 2150d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->reason = "RENEW"; 2151d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan else 2152d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->reason = "REBIND"; 2153d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } else if (state->state == DHS_REBOOT) 2154d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->reason = "REBOOT"; 2155d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan else 2156d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->reason = "BOUND"; 2157d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 21589177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan 21599177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan if (state->old && state->old->yiaddr == state->new->yiaddr && 21609177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan (state->state == DHS_REBOOT || state->state == DHS_RENEW || 21619177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan state->state == DHS_REBIND)) { 21629177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan /* Some DHCP servers respond to REQUEST with a subset 21639177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan * of the original requested parameters. If they were not 21649177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan * supplied in the response to a renewal, we should assume 21659177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan * that it's reasonable to transfer them forward from the 21669177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan * original offer. */ 21679177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan merge_option_values(state->old, state->new, ifo->requestmask); 21689177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan } 21699177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan 2170d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (lease->leasetime == ~0U) 2171d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan lease->renewaltime = lease->rebindtime = lease->leasetime; 2172d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan else { 2173d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan eloop_timeout_add_sec(ifp->ctx->eloop, 2174d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan (time_t)lease->renewaltime, dhcp_renew, ifp); 2175d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan eloop_timeout_add_sec(ifp->ctx->eloop, 2176d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan (time_t)lease->rebindtime, dhcp_rebind, ifp); 2177d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan eloop_timeout_add_sec(ifp->ctx->eloop, 2178d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan (time_t)lease->leasetime, dhcp_expire, ifp); 2179d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_DEBUG, 2180d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%s: renew in %"PRIu32" seconds, rebind in %"PRIu32 2181d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan " seconds", 2182d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->name, lease->renewaltime, lease->rebindtime); 2183d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 2184d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (!(ifo->options & DHCPCD_STATIC) && 2185d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->new->cookie != htonl(MAGIC_COOKIE)) 2186d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->state = DHS_IPV4LL_BOUND; 2187d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan else 2188d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->state = DHS_BOUND; 2189d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (!state->lease.frominfo && 2190d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan !(ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC))) 2191d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (write_lease(ifp, state->new) == -1) 2192d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_ERR, 2193d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%s: write_lease: %m", __func__); 2194d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 2195d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanapplyaddr: 2196d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ipv4_applyaddr(ifp); 2197d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifo->options & DHCPCD_ARP && 2198d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan !(ifp->ctx->options & DHCPCD_FORKED)) 2199d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { 2200d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef IN_IFF_TENTATIVE 2201d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (astate) 2202d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan arp_free_but(astate); 2203d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan else if (!ipv4ll) 2204d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan arp_close(ifp); 2205d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#else 2206d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state->added) { 2207d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (astate == NULL) { 2208d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan astate = arp_new(ifp, &state->addr); 2209d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan astate->announced_cb = 2210d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_arp_announced; 2211d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 2212d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (astate) { 2213d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan arp_announce(astate); 2214d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (!ipv4ll) 2215d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan arp_free_but(astate); 2216d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 2217d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } else if (!ipv4ll) 2218d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan arp_close(ifp); 2219d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif 2220d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 2221d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 2222d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 2223d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void 2224d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_timeout(void *arg) 2225d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 2226d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct interface *ifp = arg; 2227d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct dhcp_state *state = D_STATE(ifp); 2228d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 2229d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_bind(ifp, NULL); 2230d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->interval = 0; 2231d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_discover(ifp); 2232d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 2233d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 2234d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstruct dhcp_message * 2235d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_message_new(const struct in_addr *addr, const struct in_addr *mask) 2236d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 2237d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct dhcp_message *dhcp; 2238d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan uint8_t *p; 2239d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 2240d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp = calloc(1, sizeof(*dhcp)); 2241d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (dhcp == NULL) 2242d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return NULL; 2243d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp->yiaddr = addr->s_addr; 2244d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p = dhcp->options; 2245d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (mask && mask->s_addr != INADDR_ANY) { 2246d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *p++ = DHO_SUBNETMASK; 2247d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *p++ = sizeof(mask->s_addr); 2248d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan memcpy(p, &mask->s_addr, sizeof(mask->s_addr)); 2249d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p+= sizeof(mask->s_addr); 2250d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 2251d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *p++ = DHO_END; 2252d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return dhcp; 2253d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 2254d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 2255d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void 2256d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_static(struct interface *ifp) 2257d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 2258d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct if_options *ifo; 2259d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct dhcp_state *state; 2260d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 2261d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state = D_STATE(ifp); 2262d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifo = ifp->options; 2263d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifo->req_addr.s_addr == INADDR_ANY) { 2264d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_INFO, 2265d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%s: waiting for 3rd party to " 2266d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "configure IP address", 2267d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->name); 2268d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->reason = "3RDPARTY"; 2269d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan script_runreason(ifp, state->reason); 2270d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 2271d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 2272d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->offer = dhcp_message_new(&ifo->req_addr, &ifo->req_mask); 2273d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state->offer) { 2274d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); 2275d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_bind(ifp, NULL); 2276d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 2277d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 2278d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 2279d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanvoid 2280d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_inform(struct interface *ifp) 2281d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 2282d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct dhcp_state *state; 2283d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct if_options *ifo; 2284d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct ipv4_addr *ap; 2285d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 2286d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state = D_STATE(ifp); 2287d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifo = ifp->options; 2288d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifp->ctx->options & DHCPCD_TEST) { 2289d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->addr.s_addr = ifo->req_addr.s_addr; 2290d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->net.s_addr = ifo->req_mask.s_addr; 2291d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } else { 2292d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifo->req_addr.s_addr == INADDR_ANY) { 2293d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state = D_STATE(ifp); 2294d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ap = ipv4_iffindaddr(ifp, NULL, NULL); 2295d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ap == NULL) { 2296d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_INFO, 2297d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%s: waiting for 3rd party to " 2298d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "configure IP address", 2299d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->name); 2300d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->reason = "3RDPARTY"; 2301d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan script_runreason(ifp, state->reason); 2302d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 2303d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 2304d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->offer = 2305d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_message_new(&ap->addr, &ap->net); 2306d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } else 2307d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->offer = 2308d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_message_new(&ifo->req_addr, &ifo->req_mask); 2309d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state->offer) { 2310d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifo->options |= DHCPCD_STATIC; 2311d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_bind(ifp, NULL); 2312d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifo->options &= ~DHCPCD_STATIC; 2313d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 2314d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 2315d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 231623ff6edd8b4ec796a32d36a3eca8a8d8c785b565Samuel Tan rpc_signal_status("Inform"); 2317d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->state = DHS_INFORM; 2318d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->xid = dhcp_xid(ifp); 2319d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan send_inform(ifp); 2320d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 2321d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 2322d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanvoid 2323d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_reboot_newopts(struct interface *ifp, unsigned long long oldopts) 2324d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 2325d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct if_options *ifo; 2326d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct dhcp_state *state = D_STATE(ifp); 2327d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 2328d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state == NULL) 2329d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 2330d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifo = ifp->options; 2331d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if ((ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC) && 2332d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->addr.s_addr != ifo->req_addr.s_addr) || 2333d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan (oldopts & (DHCPCD_INFORM | DHCPCD_STATIC) && 2334d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan !(ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC)))) 2335d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { 2336d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_drop(ifp, "EXPIRE"); 2337d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 2338d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 2339d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 2340f20514bf582d08567217a3b06171bab5a11458eaSamuel Tanstatic void start_unicast_arp(struct interface *ifp); 2341f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan 2342d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void 2343d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_reboot(struct interface *ifp) 2344d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 2345d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct if_options *ifo; 2346d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct dhcp_state *state = D_STATE(ifp); 2347d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 2348d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state == NULL) 2349d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 235023ff6edd8b4ec796a32d36a3eca8a8d8c785b565Samuel Tan rpc_signal_status("Reboot"); 2351d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifo = ifp->options; 2352d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->state = DHS_REBOOT; 2353d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->interval = 0; 2354d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 2355d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifo->options & DHCPCD_LINK && ifp->carrier == LINK_DOWN) { 2356d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_INFO, 2357d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%s: waiting for carrier", ifp->name); 2358d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 2359d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 2360d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifo->options & DHCPCD_STATIC) { 2361d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_static(ifp); 2362d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 2363d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 2364f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan if (ifo->options & DHCPCD_UNICAST_ARP) { 2365f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan start_unicast_arp(ifp); 2366f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan } 2367d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifo->options & DHCPCD_INFORM) { 2368d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_INFO, "%s: informing address of %s", 2369d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->name, inet_ntoa(state->lease.addr)); 2370d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_inform(ifp); 2371d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 2372d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 2373d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifo->reboot == 0 || state->offer == NULL) { 2374d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_discover(ifp); 2375d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 2376d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 2377d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state->offer->cookie == 0) 2378d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 2379d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 2380d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_INFO, "%s: rebinding lease of %s", 2381d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->name, inet_ntoa(state->lease.addr)); 2382d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->xid = dhcp_xid(ifp); 2383d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->lease.server.s_addr = 0; 2384d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); 2385d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 2386d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* Need to add this before dhcp_expire and friends. */ 2387d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (!ifo->fallback && ifo->options & DHCPCD_IPV4LL && 2388d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan !IN_LINKLOCAL(htonl(state->addr.s_addr))) 2389d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan eloop_timeout_add_sec(ifp->ctx->eloop, 2390d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifo->reboot, ipv4ll_start, ifp); 2391d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 2392d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifo->options & DHCPCD_LASTLEASE && state->lease.frominfo) 2393d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan eloop_timeout_add_sec(ifp->ctx->eloop, 2394d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifo->reboot, dhcp_timeout, ifp); 2395d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan else if (!(ifo->options & DHCPCD_INFORM)) 2396d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan eloop_timeout_add_sec(ifp->ctx->eloop, 2397d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifo->reboot, dhcp_expire, ifp); 2398d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 2399d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* Don't bother ARP checking as the server could NAK us first. 2400d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * Don't call dhcp_request as that would change the state */ 2401d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan send_request(ifp); 2402d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 2403d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 2404d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanvoid 2405d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_drop(struct interface *ifp, const char *reason) 2406d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 2407d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct dhcp_state *state; 2408d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef RELEASE_SLOW 2409d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct timespec ts; 2410d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif 2411d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 2412d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state = D_STATE(ifp); 2413d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* dhcp_start may just have been called and we don't yet have a state 2414d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * but we do have a timeout, so punt it. */ 2415d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state == NULL) { 2416d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); 2417d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 2418d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 2419d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* Don't reset DHCP state if we have an IPv4LL address and link is up, 2420d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * unless the interface is departing. */ 2421d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state->state != DHS_IPV4LL_BOUND || 2422d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->carrier != LINK_UP || 2423d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->options->options & DHCPCD_DEPARTED) 2424d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { 2425d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); 2426d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_auth_reset(&state->auth); 2427d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_close(ifp); 2428d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 2429d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 2430d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifp->options->options & DHCPCD_RELEASE) { 2431d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan unlink(state->leasefile); 2432d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifp->carrier != LINK_DOWN && 2433d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->new != NULL && 2434d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->new->cookie == htonl(MAGIC_COOKIE)) 2435d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { 2436d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_INFO, "%s: releasing lease of %s", 2437d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->name, inet_ntoa(state->lease.addr)); 2438d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->xid = dhcp_xid(ifp); 2439d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan send_message(ifp, DHCP_RELEASE, NULL); 2440d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef RELEASE_SLOW 2441d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* Give the packet a chance to go */ 2442d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ts.tv_sec = RELEASE_DELAY_S; 2443d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ts.tv_nsec = RELEASE_DELAY_NS; 2444d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan nanosleep(&ts, NULL); 2445d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif 2446d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 2447d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 2448d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 2449d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan free(state->old); 2450d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->old = state->new; 2451d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->new = NULL; 2452d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->reason = reason; 2453d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ipv4_applyaddr(ifp); 2454d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan free(state->old); 2455d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->old = NULL; 2456d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->lease.addr.s_addr = 0; 2457d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->options->options &= ~(DHCPCD_CSR_WARNED | 2458d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan DHCPCD_ROUTER_HOST_ROUTE_WARNED); 2459d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 2460d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 2461d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void 2462d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanlog_dhcp1(int lvl, const char *msg, 2463d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan const struct interface *ifp, const struct dhcp_message *dhcp, 2464d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan const struct in_addr *from, int ad) 2465d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 2466d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan const char *tfrom; 2467d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan char *a, sname[sizeof(dhcp->servername) * 4]; 2468d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct in_addr addr; 2469d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan int r; 2470d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 2471d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (strcmp(msg, "NAK:") == 0) { 2472d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan a = get_option_string(ifp->ctx, dhcp, DHO_MESSAGE); 2473d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (a) { 2474d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan char *tmp; 2475d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan size_t al, tmpl; 2476d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 2477d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan al = strlen(a); 2478d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan tmpl = (al * 4) + 1; 2479d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan tmp = malloc(tmpl); 2480d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (tmp == NULL) { 2481d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_ERR, "%s: %m", __func__); 2482d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan free(a); 2483d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 2484d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 2485d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan print_string(tmp, tmpl, STRING, (uint8_t *)a, al); 2486d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan free(a); 2487d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan a = tmp; 2488d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 2489d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } else if (ad && dhcp->yiaddr != 0) { 2490d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan addr.s_addr = dhcp->yiaddr; 2491d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan a = strdup(inet_ntoa(addr)); 2492d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (a == NULL) { 2493d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_ERR, "%s: %m", __func__); 2494d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 2495d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 2496d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } else 2497d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan a = NULL; 2498d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 2499d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan tfrom = "from"; 2500d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan r = get_option_addr(ifp->ctx, &addr, dhcp, DHO_SERVERID); 2501d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (dhcp->servername[0] && r == 0) { 2502d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan print_string(sname, sizeof(sname), STRING, 2503d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp->servername, strlen((const char *)dhcp->servername)); 2504d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (a == NULL) 2505d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, lvl, "%s: %s %s %s `%s'", 2506d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->name, msg, tfrom, inet_ntoa(addr), sname); 2507d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan else 2508d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, lvl, "%s: %s %s %s %s `%s'", 2509d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->name, msg, a, tfrom, inet_ntoa(addr), sname); 2510d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } else { 2511d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (r != 0) { 2512d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan tfrom = "via"; 2513d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan addr = *from; 2514d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 2515d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (a == NULL) 2516d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, lvl, "%s: %s %s %s", 2517d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->name, msg, tfrom, inet_ntoa(addr)); 2518d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan else 2519d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, lvl, "%s: %s %s %s %s", 2520d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->name, msg, a, tfrom, inet_ntoa(addr)); 2521d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 2522d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan free(a); 2523d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 2524d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 2525d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void 2526d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanlog_dhcp(int lvl, const char *msg, 2527d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan const struct interface *ifp, const struct dhcp_message *dhcp, 2528d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan const struct in_addr *from) 2529d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 2530d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 2531d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan log_dhcp1(lvl, msg, ifp, dhcp, from, 1); 2532d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 2533d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 2534d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int 2535d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanblacklisted_ip(const struct if_options *ifo, in_addr_t addr) 2536d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 2537d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan size_t i; 2538d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 2539d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan for (i = 0; i < ifo->blacklist_len; i += 2) 2540d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifo->blacklist[i] == (addr & ifo->blacklist[i + 1])) 2541d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return 1; 2542d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return 0; 2543d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 2544d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 2545d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int 2546d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanwhitelisted_ip(const struct if_options *ifo, in_addr_t addr) 2547d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 2548d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan size_t i; 2549d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 2550d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifo->whitelist_len == 0) 2551d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return -1; 2552d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan for (i = 0; i < ifo->whitelist_len; i += 2) 2553d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifo->whitelist[i] == (addr & ifo->whitelist[i + 1])) 2554d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return 1; 2555d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return 0; 2556d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 2557d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 2558d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void 2559f20514bf582d08567217a3b06171bab5a11458eaSamuel Tansave_gateway_addr(struct interface *ifp, const uint8_t *gw_hwaddr) 2560f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan{ 2561f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan struct dhcp_state *state = D_STATE(ifp); 2562f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan memcpy(state->server_info.gw_hwaddr, gw_hwaddr, ifp->hwlen); 2563f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan state->server_info.gw_hwlen = ifp->hwlen; 2564f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan} 2565f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan 2566f20514bf582d08567217a3b06171bab5a11458eaSamuel Tanstatic void 2567f20514bf582d08567217a3b06171bab5a11458eaSamuel Tandhcp_probe_gw_timeout(struct arp_state *astate) 2568f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan{ 25691c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan struct dhcp_state *state = D_STATE(astate->iface); 25701c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan 2571f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan /* Ignore unicast ARP failures. */ 2572f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan if (astate->dest_hwlen) 2573f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan return; 2574f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan 2575f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan /* Probegw failure, allow ourselves to fail only once this way */ 25761c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan logger(astate->iface->ctx, LOG_ERR, 25771c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan "%s: Probe gateway %s timed out ", 25781c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan astate->iface->name, inet_ntoa(astate->addr)); 25791c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan astate->iface->options->options &= ~DHCPCD_ARPGW; 25801c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan 25811c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan unlink(state->leasefile); 25821c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan if (!state->lease.frominfo) 25831c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan dhcp_decline(astate->iface); 25841c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan#ifdef IN_IFF_DUPLICATED 25851c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan ia = ipv4_iffindaddr(astate->iface, &astate->addr, NULL); 25861c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan if (ia) 25871c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan ipv4_deladdr(astate->iface, &ia->addr, &ia->net); 25881c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan#endif 25891c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan eloop_timeout_delete(astate->iface->ctx->eloop, NULL, 25901c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan astate->iface); 25911c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan eloop_timeout_add_sec(astate->iface->ctx->eloop, 25921c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan DHCP_RAND_MAX, dhcp_discover, astate->iface); 25931c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan} 25941c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan 25951c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tanstatic void 25961c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tandhcp_probe_gw_response(struct arp_state *astate, const struct arp_msg *amsg) 25971c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan{ 25981c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan /* Verify this is a response for the gateway probe. */ 25991c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan if (astate->src_addr.s_addr != 0 && 26001c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan amsg && 26011c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan amsg->tip.s_addr == astate->src_addr.s_addr && 26021c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan amsg->sip.s_addr == astate->addr.s_addr) { 2603f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan if (astate->dest_hwlen) { 2604f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan /* Response to unicast ARP. */ 260523ff6edd8b4ec796a32d36a3eca8a8d8c785b565Samuel Tan rpc_notify_unicast_arp(astate->iface); 2606f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan } else { 2607f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan /* Response to arpgw request. */ 2608f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan save_gateway_addr(astate->iface, amsg->sha); 2609f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan 2610f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan dhcp_close(astate->iface); 2611f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan eloop_timeout_delete(astate->iface->ctx->eloop, 2612f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan NULL, astate->iface); 2613f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan #ifdef IN_IFF_TENTATIVE 2614f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan ipv4_finaliseaddr(astate->iface); 2615f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan #else 2616f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan dhcp_bind(astate->iface, NULL); 2617f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan #endif 2618f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan } 26191c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan arp_close(astate->iface); 26201c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan } 26211c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan} 26221c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan 26231c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tanstatic int 26241c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tandhcp_probe_gw(struct interface *ifp) 26251c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan{ 26261c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan struct dhcp_state *state = D_STATE(ifp); 26271c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan struct arp_state *astate; 26281c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan struct in_addr gateway_addr; 26291c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan 26301c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan if (get_option_addr(ifp->ctx, &gateway_addr, 26311c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan state->offer, DHO_ROUTER) == 0) { 26321c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan astate = arp_new(ifp, &gateway_addr); 26331c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan if (astate) { 26341c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan astate->src_addr.s_addr = state->offer->yiaddr; 26351c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan astate->probed_cb = dhcp_probe_gw_timeout; 26361c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan astate->conflicted_cb = dhcp_probe_gw_response; 26371c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan arp_probe(astate); 26381c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan return 1; 26391c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan } 26401c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan } 26411c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan return 0; 26421c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan} 26431c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan 26441c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tanstatic void 2645f20514bf582d08567217a3b06171bab5a11458eaSamuel Tanstart_unicast_arp(struct interface *ifp) 2646f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan{ 2647f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan struct dhcp_state *state = D_STATE(ifp); 2648f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan struct in_addr gwa; 2649f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan struct in_addr src_addr; 2650f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan struct arp_state *astate; 2651f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan 2652f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan if (!state->offer) 2653f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan return; 2654f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan 2655f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan if (!state->lease.frominfo) 2656f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan return; 2657f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan 2658f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan if (state->server_info.gw_hwlen != ifp->hwlen) 2659f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan return; 2660f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan 2661f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan if (get_option_addr(ifp->ctx, &gwa, state->offer, DHO_ROUTER)) 2662f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan return; 2663f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan 2664f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan astate = arp_new(ifp, &gwa); 2665f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan if (!astate) 2666f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan return; 2667f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan if (state->offer->yiaddr) 2668f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan astate->src_addr.s_addr = state->offer->yiaddr; 2669f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan else 2670f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan astate->src_addr.s_addr = state->offer->ciaddr; 2671f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan astate->probed_cb = dhcp_probe_gw_timeout; 2672f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan astate->conflicted_cb = dhcp_probe_gw_response; 2673f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan astate->dest_hwlen = state->server_info.gw_hwlen; 2674f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan memcpy(astate->dest_hwaddr, state->server_info.gw_hwaddr, 2675f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan state->server_info.gw_hwlen); 2676f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan 2677f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan arp_probe(astate); 2678f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan 2679f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan /* Invalidate our gateway address until the next successful PROBEGW. */ 2680f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan state->server_info.gw_hwlen = 0; 2681f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan} 2682f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan 2683f20514bf582d08567217a3b06171bab5a11458eaSamuel Tanstatic void 2684d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_arp_probed(struct arp_state *astate) 2685d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 2686d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct dhcp_state *state; 2687d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct if_options *ifo; 2688d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 2689d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* We didn't find a profile for this 2690d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * address or hwaddr, so move to the next 2691d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * arping profile */ 2692d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state = D_STATE(astate->iface); 2693d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifo = astate->iface->options; 2694d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state->arping_index < ifo->arping_len) { 2695d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (++state->arping_index < ifo->arping_len) { 2696d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan astate->addr.s_addr = 2697d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifo->arping[state->arping_index - 1]; 2698d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan arp_probe(astate); 2699d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 2700d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcpcd_startinterface(astate->iface); 2701d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 2702d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 27031c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan 27041c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan /* Probe the gateway specified in the lease offer. */ 27051c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan if ((ifo->options & DHCPCD_ARPGW) && (dhcp_probe_gw(astate->iface))) { 27061c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan return; 27071c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan } 27081c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan 2709d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_close(astate->iface); 2710d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan eloop_timeout_delete(astate->iface->ctx->eloop, NULL, astate->iface); 2711d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef IN_IFF_TENTATIVE 2712d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ipv4_finaliseaddr(astate->iface); 2713d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan arp_close(astate->iface); 2714d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#else 2715d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_bind(astate->iface, astate); 2716d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif 2717d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 2718d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 2719d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void 2720d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_arp_conflicted(struct arp_state *astate, const struct arp_msg *amsg) 2721d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 2722d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct dhcp_state *state; 2723d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct if_options *ifo; 2724d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 2725d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state = D_STATE(astate->iface); 2726d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifo = astate->iface->options; 2727d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state->arping_index && 2728d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->arping_index <= ifo->arping_len && 2729d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan amsg && 2730d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan (amsg->sip.s_addr == ifo->arping[state->arping_index - 1] || 2731d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan (amsg->sip.s_addr == 0 && 2732d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan amsg->tip.s_addr == ifo->arping[state->arping_index - 1]))) 2733d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { 2734d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan char buf[HWADDR_LEN * 3]; 2735d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 2736d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan astate->failed.s_addr = ifo->arping[state->arping_index - 1]; 2737d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan arp_report_conflicted(astate, amsg); 2738d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan hwaddr_ntoa(amsg->sha, astate->iface->hwlen, buf, sizeof(buf)); 2739d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (dhcpcd_selectprofile(astate->iface, buf) == -1 && 2740d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcpcd_selectprofile(astate->iface, 2741d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan inet_ntoa(astate->failed)) == -1) 2742d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { 2743d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* We didn't find a profile for this 2744d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * address or hwaddr, so move to the next 2745d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * arping profile */ 2746d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_arp_probed(astate); 2747d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 2748d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 2749d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_close(astate->iface); 2750d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan arp_close(astate->iface); 2751d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan eloop_timeout_delete(astate->iface->ctx->eloop, NULL, 2752d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan astate->iface); 2753d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcpcd_startinterface(astate->iface); 2754d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 2755d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 2756d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* RFC 2131 3.1.5, Client-server interaction 2757d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * NULL amsg means IN_IFF_DUPLICATED */ 2758d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (amsg == NULL || (state->offer && 2759d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan (amsg->sip.s_addr == state->offer->yiaddr || 2760d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan (amsg->sip.s_addr == 0 && 2761d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan amsg->tip.s_addr == state->offer->yiaddr)))) 2762d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { 2763d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef IN_IFF_DUPLICATED 2764d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct ipv4_addr *ia; 2765d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif 2766d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 27675158c9dfe576a285663b4ba16828fd6e9b35779cSamuel Tan if (amsg) { 2768d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan astate->failed.s_addr = state->offer->yiaddr; 27695158c9dfe576a285663b4ba16828fd6e9b35779cSamuel Tan state->failed.s_addr = state->offer->yiaddr; 27705158c9dfe576a285663b4ba16828fd6e9b35779cSamuel Tan } else { 2771d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan astate->failed = astate->addr; 27725158c9dfe576a285663b4ba16828fd6e9b35779cSamuel Tan state->failed = astate->addr; 27735158c9dfe576a285663b4ba16828fd6e9b35779cSamuel Tan } 27745158c9dfe576a285663b4ba16828fd6e9b35779cSamuel Tan 2775d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan arp_report_conflicted(astate, amsg); 2776d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan unlink(state->leasefile); 2777d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (!state->lease.frominfo) 2778d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_decline(astate->iface); 2779d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef IN_IFF_DUPLICATED 2780d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ia = ipv4_iffindaddr(astate->iface, &astate->addr, NULL); 2781d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ia) 2782d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ipv4_deladdr(astate->iface, &ia->addr, &ia->net); 2783d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif 278411464a5b08c94f30b5e7b59731e972b8c5bd4099Samuel Tan arp_close(astate->iface); 2785d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan eloop_timeout_delete(astate->iface->ctx->eloop, NULL, 2786d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan astate->iface); 2787d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan eloop_timeout_add_sec(astate->iface->ctx->eloop, 2788d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan DHCP_RAND_MAX, dhcp_discover, astate->iface); 2789d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 2790d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 2791d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 2792d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void 2793b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tanhandle_nak(void *arg) 2794b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tan{ 2795b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tan struct interface *ifp = arg; 2796b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tan struct dhcp_state *state = D_STATE(ifp); 2797b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tan 2798b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tan logger(ifp->ctx, LOG_INFO, "%s: Handling deferred NAK", ifp->name); 2799b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tan if (!(ifp->ctx->options & DHCPCD_TEST)) { 2800b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tan dhcp_drop(ifp, "NAK"); 2801b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tan unlink(state->leasefile); 2802b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tan } 2803b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tan 2804b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tan /* If we constantly get NAKS then we should slowly back off */ 2805b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tan eloop_timeout_add_sec(ifp->ctx->eloop, 2806b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tan state->nakoff, dhcp_discover, ifp); 2807b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tan if (state->nakoff == 0) 2808b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tan state->nakoff = 1; 2809b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tan else { 2810b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tan state->nakoff *= 2; 2811b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tan if (state->nakoff > NAKOFF_MAX) 2812b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tan state->nakoff = NAKOFF_MAX; 2813b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tan } 2814b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tan} 2815b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tan 2816b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tanstatic void 2817d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_handledhcp(struct interface *ifp, struct dhcp_message **dhcpp, 2818d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan const struct in_addr *from) 2819d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 2820d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct dhcp_state *state = D_STATE(ifp); 2821d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct if_options *ifo = ifp->options; 2822d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct dhcp_message *dhcp = *dhcpp; 2823d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct dhcp_lease *lease = &state->lease; 2824d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan uint8_t type, tmp; 2825d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan const uint8_t *auth; 2826d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct in_addr addr; 2827d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan unsigned int i; 2828d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan size_t auth_len; 2829d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan char *msg; 2830d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct arp_state *astate; 2831d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct ipv4_addr *ia; 2832d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 2833d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* We may have found a BOOTP server */ 2834d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (get_option_uint8(ifp->ctx, &type, dhcp, DHO_MESSAGETYPE) == -1) 2835d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan type = 0; 2836d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan else if (ifo->options & DHCPCD_BOOTP) { 2837d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_DEBUG, 2838d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%s: ignoring DHCP reply (excpecting BOOTP)", 2839d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->name); 2840d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 2841d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 2842d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 2843d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* Authenticate the message */ 2844d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan auth = get_option(ifp->ctx, dhcp, DHO_AUTHENTICATION, &auth_len); 2845d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (auth) { 2846d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (dhcp_auth_validate(&state->auth, &ifo->auth, 2847d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan (uint8_t *)*dhcpp, sizeof(**dhcpp), 4, type, 2848d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan auth, auth_len) == NULL) 2849d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { 2850d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_DEBUG, 2851d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%s: dhcp_auth_validate: %m", ifp->name); 2852d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan log_dhcp1(LOG_ERR, "authentication failed", 2853d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp, dhcp, from, 0); 2854d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 2855d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 2856d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state->auth.token) 2857d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_DEBUG, 2858d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%s: validated using 0x%08" PRIu32, 2859d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->name, state->auth.token->secretid); 2860d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan else 2861d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_DEBUG, 2862d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%s: accepted reconfigure key", ifp->name); 2863d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } else if (ifo->auth.options & DHCPCD_AUTH_REQUIRE) { 2864d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan log_dhcp1(LOG_ERR, "no authentication", ifp, dhcp, from, 0); 2865d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 2866d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } else if (ifo->auth.options & DHCPCD_AUTH_SEND) 2867d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan log_dhcp1(LOG_WARNING, "no authentication", 2868d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp, dhcp, from, 0); 2869d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 2870d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* RFC 3203 */ 2871d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (type == DHCP_FORCERENEW) { 2872d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (from->s_addr == INADDR_ANY || 2873d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan from->s_addr == INADDR_BROADCAST) 2874d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { 2875d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan log_dhcp(LOG_ERR, "discarding Force Renew", 2876d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp, dhcp, from); 2877d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 2878d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 2879d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (auth == NULL) { 2880d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan log_dhcp(LOG_ERR, "unauthenticated Force Renew", 2881d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp, dhcp, from); 2882d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 2883d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 2884d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state->state != DHS_BOUND && state->state != DHS_INFORM) { 2885d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan log_dhcp(LOG_DEBUG, "not bound, ignoring Force Renew", 2886d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp, dhcp, from); 2887d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 2888d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 2889d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan log_dhcp(LOG_ERR, "Force Renew from", ifp, dhcp, from); 2890d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* The rebind and expire timings are still the same, we just 2891d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * enter the renew state early */ 2892d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state->state == DHS_BOUND) { 2893d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan eloop_timeout_delete(ifp->ctx->eloop, 2894d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_renew, ifp); 2895d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_renew(ifp); 2896d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } else { 2897d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan eloop_timeout_delete(ifp->ctx->eloop, 2898d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan send_inform, ifp); 2899d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_inform(ifp); 2900d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 2901d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 2902d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 2903d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 2904d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state->state == DHS_BOUND) { 2905d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* Before we supported FORCERENEW we closed off the raw 2906d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * port so we effectively ignored all messages. 2907d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * As such we'll not log by default here. */ 2908d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan //log_dhcp(LOG_DEBUG, "bound, ignoring", iface, dhcp, from); 2909d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 2910d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 2911d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 2912d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* Ensure it's the right transaction */ 2913d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state->xid != ntohl(dhcp->xid)) { 2914d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_DEBUG, 2915d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%s: wrong xid 0x%x (expecting 0x%x) from %s", 2916d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->name, ntohl(dhcp->xid), state->xid, 2917d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan inet_ntoa(*from)); 2918d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 2919d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 2920d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* reset the message counter */ 2921d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->interval = 0; 2922d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 2923d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* Ensure that no reject options are present */ 2924d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan for (i = 1; i < 255; i++) { 2925d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (has_option_mask(ifo->rejectmask, i) && 2926d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan get_option_uint8(ifp->ctx, &tmp, dhcp, (uint8_t)i) == 0) 2927d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { 2928d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan log_dhcp(LOG_WARNING, "reject DHCP", ifp, dhcp, from); 2929d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 2930d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 2931d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 2932d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 2933d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (type == DHCP_NAK) { 2934d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if ((msg = get_option_string(ifp->ctx, dhcp, DHO_MESSAGE))) { 2935d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_WARNING, "%s: message: %s", 2936d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->name, msg); 2937d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan free(msg); 2938d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 2939d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state->state == DHS_INFORM) /* INFORM should not be NAKed */ 2940d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 2941d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 2942b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tan log_dhcp(LOG_WARNING, "NAK (deferred):", ifp, dhcp, from); 294323ff6edd8b4ec796a32d36a3eca8a8d8c785b565Samuel Tan rpc_signal_status("NakDefer"); 29445158c9dfe576a285663b4ba16828fd6e9b35779cSamuel Tan if (state->nak_receive_count == 0) 29455158c9dfe576a285663b4ba16828fd6e9b35779cSamuel Tan eloop_timeout_add_sec(ifp->ctx->eloop, 29465158c9dfe576a285663b4ba16828fd6e9b35779cSamuel Tan DHCP_BASE, handle_nak, ifp); 29475158c9dfe576a285663b4ba16828fd6e9b35779cSamuel Tan state->nak_receive_count++; 2948d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 2949d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 2950d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 2951d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* Ensure that all required options are present */ 2952d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan for (i = 1; i < 255; i++) { 2953d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (has_option_mask(ifo->requiremask, i) && 2954d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan get_option_uint8(ifp->ctx, &tmp, dhcp, (uint8_t)i) != 0) 2955d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { 2956d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* If we are BOOTP, then ignore the need for serverid. 2957d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * To ignore BOOTP, require dhcp_message_type. 2958d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * However, nothing really stops BOOTP from providing 2959d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * DHCP style options as well so the above isn't 2960d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * always true. */ 2961d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (type == 0 && i == DHO_SERVERID) 2962d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan continue; 2963d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan log_dhcp(LOG_WARNING, "reject DHCP", ifp, dhcp, from); 2964d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 2965d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 2966d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 2967d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 2968d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* DHCP Auto-Configure, RFC 2563 */ 2969d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (type == DHCP_OFFER && dhcp->yiaddr == 0) { 2970d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan log_dhcp(LOG_WARNING, "no address given", ifp, dhcp, from); 2971d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if ((msg = get_option_string(ifp->ctx, dhcp, DHO_MESSAGE))) { 2972d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_WARNING, 2973d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%s: message: %s", ifp->name, msg); 2974d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan free(msg); 2975d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 2976d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if ((state->state == DHS_DISCOVER || 2977d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->state == DHS_IPV4LL_BOUND) && 2978d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan get_option_uint8(ifp->ctx, &tmp, dhcp, 2979d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan DHO_AUTOCONFIGURE) == 0) 2980d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { 2981d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan switch (tmp) { 2982d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan case 0: 2983d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan log_dhcp(LOG_WARNING, "IPv4LL disabled from", 2984d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp, dhcp, from); 2985d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_drop(ifp, "EXPIRE"); 2986d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan arp_close(ifp); 2987d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan eloop_timeout_delete(ifp->ctx->eloop, 2988d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan NULL, ifp); 2989d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan eloop_timeout_add_sec(ifp->ctx->eloop, 2990d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan DHCP_MAX, dhcp_discover, 2991d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp); 2992d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan break; 2993d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan case 1: 2994d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan log_dhcp(LOG_WARNING, "IPv4LL enabled from", 2995d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp, dhcp, from); 2996d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan eloop_timeout_delete(ifp->ctx->eloop, 2997d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan NULL, ifp); 2998d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (IN_LINKLOCAL(htonl(state->addr.s_addr))) 2999d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan eloop_timeout_add_sec(ifp->ctx->eloop, 3000d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan DHCP_MAX, dhcp_discover, ifp); 3001d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan else 3002d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ipv4ll_start(ifp); 3003d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan break; 3004d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan default: 3005d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_ERR, 3006d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%s: unknown auto configuration option %d", 3007d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->name, tmp); 3008d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan break; 3009d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3010d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3011d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 3012d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3013d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3014d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* Ensure that the address offered is valid */ 3015d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if ((type == 0 || type == DHCP_OFFER || type == DHCP_ACK) && 3016d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan (dhcp->ciaddr == INADDR_ANY || dhcp->ciaddr == INADDR_BROADCAST) && 3017d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan (dhcp->yiaddr == INADDR_ANY || dhcp->yiaddr == INADDR_BROADCAST)) 3018d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { 301923ff6edd8b4ec796a32d36a3eca8a8d8c785b565Samuel Tan rpc_signal_status("IgnoreInvalidOffer"); 3020d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan log_dhcp(LOG_WARNING, "reject invalid address", 3021d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp, dhcp, from); 3022d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 3023d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3024d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3025d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef IN_IFF_DUPLICATED 3026d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ia = ipv4_iffindaddr(ifp, &lease->addr, NULL); 3027d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ia && ia->addr_flags & IN_IFF_DUPLICATED) { 3028d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan log_dhcp(LOG_WARNING, "declined duplicate address", 3029d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp, dhcp, from); 3030d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (type) 3031d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_decline(ifp); 3032d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ipv4_deladdr(ifp, &ia->addr, &ia->net); 3033d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); 3034d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan eloop_timeout_add_sec(ifp->ctx->eloop, 3035d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan DHCP_RAND_MAX, dhcp_discover, ifp); 3036d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 3037d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3038d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif 3039d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3040d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if ((type == 0 || type == DHCP_OFFER) && 3041d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan (state->state == DHS_DISCOVER || state->state == DHS_IPV4LL_BOUND)) 3042d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { 30435158c9dfe576a285663b4ba16828fd6e9b35779cSamuel Tan if (dhcp->yiaddr == state->failed.s_addr && 30445158c9dfe576a285663b4ba16828fd6e9b35779cSamuel Tan state->failed_address_offer_count == 0) { 30455158c9dfe576a285663b4ba16828fd6e9b35779cSamuel Tan log_dhcp(LOG_WARNING, 30465158c9dfe576a285663b4ba16828fd6e9b35779cSamuel Tan "reject previously declined address", 30475158c9dfe576a285663b4ba16828fd6e9b35779cSamuel Tan ifp, dhcp, from); 304823ff6edd8b4ec796a32d36a3eca8a8d8c785b565Samuel Tan rpc_signal_status("IgnoreFailedOffer"); 30495158c9dfe576a285663b4ba16828fd6e9b35779cSamuel Tan state->failed_address_offer_count++; 30505158c9dfe576a285663b4ba16828fd6e9b35779cSamuel Tan return; 30515158c9dfe576a285663b4ba16828fd6e9b35779cSamuel Tan } 3052d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan lease->frominfo = 0; 3053d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan lease->addr.s_addr = dhcp->yiaddr; 3054d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan lease->cookie = dhcp->cookie; 3055d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (type == 0 || 3056d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan get_option_addr(ifp->ctx, 3057d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan &lease->server, dhcp, DHO_SERVERID) != 0) 3058d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan lease->server.s_addr = INADDR_ANY; 3059d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan log_dhcp(LOG_INFO, "offered", ifp, dhcp, from); 3060d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan free(state->offer); 3061d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->offer = dhcp; 3062d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *dhcpp = NULL; 3063d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifp->ctx->options & DHCPCD_TEST) { 3064d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan free(state->old); 3065d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->old = state->new; 3066d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->new = state->offer; 3067d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->offer = NULL; 3068d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->reason = "TEST"; 3069d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan script_runreason(ifp, state->reason); 3070d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan eloop_exit(ifp->ctx->eloop, EXIT_SUCCESS); 3071d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 3072d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3073d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan eloop_timeout_delete(ifp->ctx->eloop, send_discover, ifp); 3074b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tan eloop_timeout_delete(ifp->ctx->eloop, handle_nak, ifp); 3075d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* We don't request BOOTP addresses */ 3076d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (type) { 3077d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* We used to ARP check here, but that seems to be in 3078d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * violation of RFC2131 where it only describes 3079d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * DECLINE after REQUEST. 3080d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * It also seems that some MS DHCP servers actually 3081d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * ignore DECLINE if no REQUEST, ie we decline a 3082d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * DISCOVER. */ 3083d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_request(ifp); 3084d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 3085d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3086d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3087d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3088d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (type) { 3089d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (type == DHCP_OFFER) { 3090d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan log_dhcp(LOG_WARNING, "ignoring offer of", 3091d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp, dhcp, from); 309223ff6edd8b4ec796a32d36a3eca8a8d8c785b565Samuel Tan rpc_signal_status("IgnoreAdditionalOffer"); 3093d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 3094d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3095d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3096d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* We should only be dealing with acks */ 3097d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (type != DHCP_ACK) { 3098d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan log_dhcp(LOG_ERR, "not ACK or OFFER", 3099d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp, dhcp, from); 310023ff6edd8b4ec796a32d36a3eca8a8d8c785b565Samuel Tan rpc_signal_status("IgnoreNonOffer"); 3101d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 3102d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3103d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3104d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (!(ifo->options & DHCPCD_INFORM)) 3105d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan log_dhcp(LOG_DEBUG, "acknowledged", ifp, dhcp, from); 3106d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan else 3107d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifo->options &= ~DHCPCD_STATIC; 3108d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3109d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3110d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3111d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* No NAK, so reset the backoff 3112d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * We don't reset on an OFFER message because the server could 3113d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * potentially NAK the REQUEST. */ 3114d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->nakoff = 0; 3115d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3116d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* BOOTP could have already assigned this above, so check we still 3117d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * have a pointer. */ 3118d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (*dhcpp) { 3119d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan free(state->offer); 3120d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->offer = dhcp; 3121d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *dhcpp = NULL; 3122d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3123d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3124d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan lease->frominfo = 0; 3125d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); 3126d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan astate = NULL; 3127d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 312847d708b8f4e037f6f224f71ea5864c90184b4ffbSamuel Tan#ifdef IN_IFF_TENTATIVE 312947d708b8f4e037f6f224f71ea5864c90184b4ffbSamuel Tan addr.s_addr = state->offer->yiaddr; 313047d708b8f4e037f6f224f71ea5864c90184b4ffbSamuel Tan astate = arp_new(ifp, &addr); 313147d708b8f4e037f6f224f71ea5864c90184b4ffbSamuel Tan if (astate) { 313247d708b8f4e037f6f224f71ea5864c90184b4ffbSamuel Tan astate->probed_cb = dhcp_arp_probed; 313347d708b8f4e037f6f224f71ea5864c90184b4ffbSamuel Tan astate->conflicted_cb = dhcp_arp_conflicted; 313447d708b8f4e037f6f224f71ea5864c90184b4ffbSamuel Tan /* No need to start the probe as we'll 313547d708b8f4e037f6f224f71ea5864c90184b4ffbSamuel Tan * listen to the kernel stating DAD or not and 313647d708b8f4e037f6f224f71ea5864c90184b4ffbSamuel Tan * that action look look for our ARP state for 313747d708b8f4e037f6f224f71ea5864c90184b4ffbSamuel Tan * what to do. */ 313847d708b8f4e037f6f224f71ea5864c90184b4ffbSamuel Tan } 313947d708b8f4e037f6f224f71ea5864c90184b4ffbSamuel Tan#else 31405158c9dfe576a285663b4ba16828fd6e9b35779cSamuel Tan if ((ifo->options & DHCPCD_ARP || state->nak_receive_count > 0 || 31415158c9dfe576a285663b4ba16828fd6e9b35779cSamuel Tan dhcp->yiaddr == state->failed.s_addr) 3142d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan && state->addr.s_addr != state->offer->yiaddr) 3143d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { 3144d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan addr.s_addr = state->offer->yiaddr; 3145d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* If the interface already has the address configured 3146d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * then we can't ARP for duplicate detection. */ 3147d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ia = ipv4_findaddr(ifp->ctx, &addr); 314847d708b8f4e037f6f224f71ea5864c90184b4ffbSamuel Tan if (ia == NULL) { 3149d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan astate = arp_new(ifp, &addr); 3150d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (astate) { 3151d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan astate->probed_cb = dhcp_arp_probed; 3152d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan astate->conflicted_cb = dhcp_arp_conflicted; 3153d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan arp_probe(astate); 315423ff6edd8b4ec796a32d36a3eca8a8d8c785b565Samuel Tan rpc_signal_status("ArpSelf"); 3155d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3156d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 3157d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3158d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 315947d708b8f4e037f6f224f71ea5864c90184b4ffbSamuel Tan#endif 3160d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 31611c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan if ((ifo->options & DHCPCD_ARPGW) && (dhcp_probe_gw(ifp))) { 316223ff6edd8b4ec796a32d36a3eca8a8d8c785b565Samuel Tan rpc_signal_status("ArpGateway"); 31631c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan return; 31641c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan } 31651c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan 3166d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_bind(ifp, astate); 3167d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 3168d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3169d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic size_t 3170d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanget_udp_data(const uint8_t **data, const uint8_t *udp) 3171d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 3172d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct udp_dhcp_packet p; 3173d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3174d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan memcpy(&p, udp, sizeof(p)); 3175d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *data = udp + offsetof(struct udp_dhcp_packet, dhcp); 3176d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return ntohs(p.ip.ip_len) - sizeof(p.ip) - sizeof(p.udp); 3177d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 3178d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3179d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int 3180d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanvalid_udp_packet(const uint8_t *data, size_t data_len, struct in_addr *from, 3181d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan int noudpcsum) 3182d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 3183d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct udp_dhcp_packet p; 3184d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan uint16_t bytes, udpsum; 3185d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3186d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (data_len < sizeof(p.ip)) { 3187d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (from) 3188d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan from->s_addr = INADDR_ANY; 3189d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan errno = EINVAL; 3190d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return -1; 3191d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3192d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan memcpy(&p, data, MIN(data_len, sizeof(p))); 3193d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (from) 3194d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan from->s_addr = p.ip.ip_src.s_addr; 3195d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (data_len > sizeof(p)) { 3196d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan errno = EINVAL; 3197d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return -1; 3198d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3199d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (checksum(&p.ip, sizeof(p.ip)) != 0) { 3200d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan errno = EINVAL; 3201d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return -1; 3202d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3203d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3204d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan bytes = ntohs(p.ip.ip_len); 3205d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (data_len < bytes) { 3206d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan errno = EINVAL; 3207d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return -1; 3208d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3209d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3210d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (noudpcsum == 0) { 3211d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan udpsum = p.udp.uh_sum; 3212d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p.udp.uh_sum = 0; 3213d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p.ip.ip_hl = 0; 3214d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p.ip.ip_v = 0; 3215d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p.ip.ip_tos = 0; 3216d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p.ip.ip_len = p.udp.uh_ulen; 3217d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p.ip.ip_id = 0; 3218d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p.ip.ip_off = 0; 3219d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p.ip.ip_ttl = 0; 3220d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p.ip.ip_sum = 0; 3221d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (udpsum && checksum(&p, bytes) != udpsum) { 3222d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan errno = EINVAL; 3223d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return -1; 3224d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3225d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3226d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3227d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return 0; 3228d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 3229d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3230d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void 3231d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_handlepacket(void *arg) 3232d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 3233d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct interface *ifp = arg; 3234d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct dhcp_message *dhcp = NULL; 3235d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan const uint8_t *pp; 3236d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan size_t bytes; 3237d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct in_addr from; 3238d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan int i, flags; 3239d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan const struct dhcp_state *state = D_CSTATE(ifp); 3240d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3241d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* Need this API due to BPF */ 3242d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan flags = 0; 3243d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan while (!(flags & RAW_EOF)) { 3244d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan bytes = (size_t)if_readrawpacket(ifp, ETHERTYPE_IP, 3245d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->ctx->packet, udp_dhcp_len, &flags); 3246d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if ((ssize_t)bytes == -1) { 3247d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_ERR, 3248d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%s: dhcp if_readrawpacket: %m", ifp->name); 3249d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_close(ifp); 3250d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan arp_close(ifp); 3251d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan break; 3252d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3253d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (valid_udp_packet(ifp->ctx->packet, bytes, 3254d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan &from, flags & RAW_PARTIALCSUM) == -1) 3255d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { 3256d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_ERR, 3257d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%s: invalid UDP packet from %s", 3258d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->name, inet_ntoa(from)); 3259d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan continue; 3260d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3261d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan i = whitelisted_ip(ifp->options, from.s_addr); 3262d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (i == 0) { 3263d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_WARNING, 3264d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%s: non whitelisted DHCP packet from %s", 3265d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->name, inet_ntoa(from)); 3266d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan continue; 3267d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } else if (i != 1 && 3268d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan blacklisted_ip(ifp->options, from.s_addr) == 1) 3269d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { 3270d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_WARNING, 3271d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%s: blacklisted DHCP packet from %s", 3272d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->name, inet_ntoa(from)); 3273d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan continue; 3274d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3275d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifp->flags & IFF_POINTOPOINT && 3276d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->dst.s_addr != from.s_addr) 3277d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { 3278d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_WARNING, 3279d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%s: server %s is not destination", 3280d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->name, inet_ntoa(from)); 3281d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3282d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan bytes = get_udp_data(&pp, ifp->ctx->packet); 3283d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (bytes > sizeof(*dhcp)) { 3284d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_ERR, 3285d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%s: packet greater than DHCP size from %s", 3286d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->name, inet_ntoa(from)); 3287d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan continue; 3288d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3289d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (dhcp == NULL) { 3290d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp = calloc(1, sizeof(*dhcp)); 3291d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (dhcp == NULL) { 3292d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_ERR, 3293d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%s: calloc: %m", __func__); 3294d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan break; 3295d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3296d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3297d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan memcpy(dhcp, pp, bytes); 3298d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (dhcp->cookie != htonl(MAGIC_COOKIE)) { 3299d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_DEBUG, "%s: bogus cookie from %s", 3300d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->name, inet_ntoa(from)); 3301d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan continue; 3302d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3303d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* Ensure packet is for us */ 3304d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifp->hwlen <= sizeof(dhcp->chaddr) && 3305d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan memcmp(dhcp->chaddr, ifp->hwaddr, ifp->hwlen)) 3306d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { 3307d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan char buf[sizeof(dhcp->chaddr) * 3]; 3308d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3309d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_DEBUG, 3310d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%s: xid 0x%x is for hwaddr %s", 3311d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->name, ntohl(dhcp->xid), 3312d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan hwaddr_ntoa(dhcp->chaddr, sizeof(dhcp->chaddr), 3313d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan buf, sizeof(buf))); 3314d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan continue; 3315d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3316d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_handledhcp(ifp, &dhcp, &from); 3317d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state->raw_fd == -1) 3318d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan break; 3319d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3320d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan free(dhcp); 3321d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 3322d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3323d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void 3324d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_handleudp(void *arg) 3325d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 3326d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct dhcpcd_ctx *ctx; 3327d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan uint8_t buffer[sizeof(struct dhcp_message)]; 3328d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3329d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ctx = arg; 3330d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3331d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* Just read what's in the UDP fd and discard it as we always read 3332d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * from the raw fd */ 3333d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (read(ctx->udp_fd, buffer, sizeof(buffer)) == -1) { 3334d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ctx, LOG_ERR, "%s: %m", __func__); 3335d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan eloop_event_delete(ctx->eloop, ctx->udp_fd, 0); 3336d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan close(ctx->udp_fd); 3337d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ctx->udp_fd = -1; 3338d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3339d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 3340d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3341d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int 3342d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_open(struct interface *ifp) 3343d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 3344d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct dhcp_state *state; 3345d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3346d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifp->ctx->packet == NULL) { 3347d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->ctx->packet = malloc(udp_dhcp_len); 3348d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifp->ctx->packet == NULL) { 3349d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_ERR, "%s: %m", __func__); 3350d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return -1; 3351d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3352d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3353d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3354d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state = D_STATE(ifp); 3355d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state->raw_fd == -1) { 3356d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->raw_fd = if_openrawsocket(ifp, ETHERTYPE_IP); 3357d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state->raw_fd == -1) { 3358d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (errno == ENOENT) { 3359d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_ERR, 3360d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%s not found", if_pfname); 3361d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* May as well disable IPv4 entirely at 3362d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * this point as we really need it. */ 3363d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->options->options &= ~DHCPCD_IPV4; 3364d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } else 3365d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_ERR, "%s: %s: %m", 3366d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan __func__, ifp->name); 3367d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return -1; 3368d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3369d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan eloop_event_add(ifp->ctx->eloop, 3370d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->raw_fd, dhcp_handlepacket, ifp, NULL, NULL); 3371d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3372d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return 0; 3373d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 3374d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3375d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanint 3376d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_dump(struct interface *ifp) 3377d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 3378d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct dhcp_state *state; 3379d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3380d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->if_data[IF_DATA_DHCP] = state = calloc(1, sizeof(*state)); 3381d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state == NULL) 3382d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan goto eexit; 3383d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->raw_fd = state->arp_fd = -1; 3384d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan TAILQ_INIT(&state->arp_states); 3385d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_set_leasefile(state->leasefile, sizeof(state->leasefile), 3386d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan AF_INET, ifp, ""); 3387d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->new = read_lease(ifp); 3388d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state->new == NULL) { 3389d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_ERR, "%s: %s: %m", 3390d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *ifp->name ? ifp->name : state->leasefile, __func__); 3391d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return -1; 3392d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3393d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->reason = "DUMP"; 3394d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return script_runreason(ifp, state->reason); 3395d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3396d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Taneexit: 3397d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_ERR, "%s: %m", __func__); 3398d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return -1; 3399d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 3400d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3401d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanvoid 3402d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_free(struct interface *ifp) 3403d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 3404d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct dhcp_state *state = D_STATE(ifp); 3405d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct dhcpcd_ctx *ctx; 3406d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3407d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_close(ifp); 3408d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan arp_close(ifp); 3409d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state) { 3410d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan free(state->old); 3411d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan free(state->new); 3412d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan free(state->offer); 3413d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan free(state->buffer); 3414d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan free(state->clientid); 3415d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan free(state); 3416d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->if_data[IF_DATA_DHCP] = NULL; 3417d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3418d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3419d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ctx = ifp->ctx; 3420d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* If we don't have any more DHCP enabled interfaces, 3421d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * close the global socket and release resources */ 3422d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ctx->ifaces) { 3423d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan TAILQ_FOREACH(ifp, ctx->ifaces, next) { 3424d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (D_STATE(ifp)) 3425d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan break; 3426d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3427d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3428d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifp == NULL) { 3429d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ctx->udp_fd != -1) { 3430d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan eloop_event_delete(ctx->eloop, ctx->udp_fd, 0); 3431d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan close(ctx->udp_fd); 3432d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ctx->udp_fd = -1; 3433d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3434d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3435d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan free(ctx->packet); 3436d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan free(ctx->opt_buffer); 3437d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ctx->packet = NULL; 3438d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ctx->opt_buffer = NULL; 3439d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3440d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 3441d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3442d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int 3443d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_init(struct interface *ifp) 3444d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 3445d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct dhcp_state *state; 3446d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan const struct if_options *ifo; 3447d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan uint8_t len; 3448d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan char buf[(sizeof(ifo->clientid) - 1) * 3]; 3449d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3450d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state = D_STATE(ifp); 3451d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state == NULL) { 3452d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->if_data[IF_DATA_DHCP] = calloc(1, sizeof(*state)); 3453d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state = D_STATE(ifp); 3454d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state == NULL) 3455d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return -1; 3456d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* 0 is a valid fd, so init to -1 */ 3457d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->raw_fd = state->arp_fd = -1; 3458d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan TAILQ_INIT(&state->arp_states); 3459d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3460d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* Now is a good time to find IPv4 routes */ 3461d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if_initrt(ifp); 3462d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3463d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3464d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->state = DHS_INIT; 3465d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->reason = "PREINIT"; 3466d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->nakoff = 0; 3467d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_set_leasefile(state->leasefile, sizeof(state->leasefile), 3468d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan AF_INET, ifp, ""); 3469d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3470d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifo = ifp->options; 3471d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* We need to drop the leasefile so that dhcp_start 3472d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * doesn't load it. */ 3473d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifo->options & DHCPCD_REQUEST) 3474d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan unlink(state->leasefile); 3475d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3476d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan free(state->clientid); 3477d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->clientid = NULL; 3478d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3479d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (*ifo->clientid) { 3480d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->clientid = malloc((size_t)(ifo->clientid[0] + 1)); 3481d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state->clientid == NULL) 3482d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan goto eexit; 3483d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan memcpy(state->clientid, ifo->clientid, 3484d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan (size_t)(ifo->clientid[0]) + 1); 3485d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } else if (ifo->options & DHCPCD_CLIENTID) { 3486d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifo->options & DHCPCD_DUID) { 3487d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->clientid = malloc(ifp->ctx->duid_len + 6); 3488d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state->clientid == NULL) 3489d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan goto eexit; 3490d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->clientid[0] =(uint8_t)(ifp->ctx->duid_len + 5); 3491d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->clientid[1] = 255; /* RFC 4361 */ 3492d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan memcpy(state->clientid + 2, ifo->iaid, 4); 3493d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan memcpy(state->clientid + 6, ifp->ctx->duid, 3494d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->ctx->duid_len); 3495d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } else { 3496d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan len = (uint8_t)(ifp->hwlen + 1); 3497d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->clientid = malloc((size_t)len + 1); 3498d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state->clientid == NULL) 3499d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan goto eexit; 3500d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->clientid[0] = len; 3501d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->clientid[1] = (uint8_t)ifp->family; 3502d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan memcpy(state->clientid + 2, ifp->hwaddr, 3503d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->hwlen); 3504d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3505d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3506d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3507d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifo->options & DHCPCD_DUID) 3508d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* Don't bother logging as DUID and IAID are reported 3509d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * at device start. */ 3510d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return 0; 3511d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3512d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifo->options & DHCPCD_CLIENTID) 3513d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_DEBUG, "%s: using ClientID %s", ifp->name, 3514d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan hwaddr_ntoa(state->clientid + 1, state->clientid[0], 3515d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan buf, sizeof(buf))); 3516d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan else if (ifp->hwlen) 3517d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_DEBUG, "%s: using hwaddr %s", ifp->name, 3518d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan hwaddr_ntoa(ifp->hwaddr, ifp->hwlen, buf, sizeof(buf))); 3519d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return 0; 3520d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3521d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Taneexit: 3522d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_ERR, "%s: error making ClientID: %m", __func__); 3523d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return -1; 3524d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 3525d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3526d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void 3527d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_start1(void *arg) 3528d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 3529d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct interface *ifp = arg; 3530d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct if_options *ifo = ifp->options; 3531d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct dhcp_state *state; 3532d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct stat st; 3533d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan uint32_t l; 3534d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan int nolease; 3535d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3536d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (!(ifo->options & DHCPCD_IPV4)) 3537d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 3538d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3539d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* Listen on *.*.*.*:bootpc so that the kernel never sends an 3540d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * ICMP port unreachable message back to the DHCP server */ 3541d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifp->ctx->udp_fd == -1) { 3542d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->ctx->udp_fd = dhcp_openudp(NULL); 3543d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifp->ctx->udp_fd == -1) { 3544d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* Don't log an error if some other process 3545d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * is handling this. */ 3546d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (errno != EADDRINUSE) 3547d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_ERR, 3548d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%s: dhcp_openudp: %m", __func__); 3549d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } else 3550d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan eloop_event_add(ifp->ctx->eloop, 3551d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->ctx->udp_fd, dhcp_handleudp, 3552d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->ctx, NULL, NULL); 3553d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3554d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3555d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (dhcp_init(ifp) == -1) { 3556d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_ERR, "%s: dhcp_init: %m", ifp->name); 3557d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 3558d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3559d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3560d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state = D_STATE(ifp); 3561d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->start_uptime = uptime(); 3562d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan free(state->offer); 3563d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->offer = NULL; 3564d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3565d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state->arping_index < ifo->arping_len) { 3566d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct arp_state *astate; 3567d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3568d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan astate = arp_new(ifp, NULL); 3569d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (astate) { 3570d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan astate->probed_cb = dhcp_arp_probed; 3571d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan astate->conflicted_cb = dhcp_arp_conflicted; 3572d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_arp_probed(astate); 3573d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3574d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 3575d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3576d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3577d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifo->options & DHCPCD_STATIC) { 3578d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_static(ifp); 3579d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 3580d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3581d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3582d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifo->options & DHCPCD_DHCP && dhcp_open(ifp) == -1) 3583d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 3584d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3585d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifo->options & DHCPCD_INFORM) { 3586d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_inform(ifp); 3587d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 3588d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3589d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifp->hwlen == 0 && ifo->clientid[0] == '\0') { 3590d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_WARNING, 3591d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%s: needs a clientid to configure", ifp->name); 3592d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_drop(ifp, "FAIL"); 3593d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); 3594d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 3595d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3596d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* We don't want to read the old lease if we NAK an old test */ 3597d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan nolease = state->offer && ifp->ctx->options & DHCPCD_TEST; 3598d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (!nolease) { 3599d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->offer = read_lease(ifp); 3600d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* Check the saved lease matches the type we want */ 3601d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state->offer) { 3602d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef IN_IFF_DUPLICATED 3603d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct in_addr addr; 3604d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct ipv4_addr *ia; 3605d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3606d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan addr.s_addr = state->offer->yiaddr; 3607d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ia = ipv4_iffindaddr(ifp, &addr, NULL); 3608d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif 3609d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3610d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if ((IS_BOOTP(ifp, state->offer) && 3611d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan !(ifo->options & DHCPCD_BOOTP)) || 3612d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef IN_IFF_DUPLICATED 3613d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan (ia && ia->addr_flags & IN_IFF_DUPLICATED) || 3614d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif 3615d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan (!IS_BOOTP(ifp, state->offer) && 3616d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifo->options & DHCPCD_BOOTP)) 3617d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { 3618d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan free(state->offer); 3619d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->offer = NULL; 3620d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3621d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3622d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3623d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state->offer) { 3624d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan get_lease(ifp->ctx, &state->lease, state->offer); 3625d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->lease.frominfo = 1; 3626d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state->new == NULL && 3627d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ipv4_iffindaddr(ifp, &state->lease.addr, &state->lease.net)) 3628d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { 3629d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* We still have the IP address from the last lease. 3630d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * Fake add the address and routes from it so the lease 3631d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * can be cleaned up. */ 3632d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->new = malloc(sizeof(*state->new)); 3633d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state->new) { 3634d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan memcpy(state->new, state->offer, 3635d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan sizeof(*state->new)); 3636d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->addr = state->lease.addr; 3637d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->net = state->lease.net; 3638d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->added |= STATE_ADDED | STATE_FAKE; 3639d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ipv4_buildroutes(ifp->ctx); 3640d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } else 3641d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_ERR, "%s: %m", __func__); 3642d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3643d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state->offer->cookie == 0) { 3644d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state->offer->yiaddr == state->addr.s_addr) { 3645d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan free(state->offer); 3646d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->offer = NULL; 3647d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3648d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } else if (state->lease.leasetime != ~0U && 3649d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan stat(state->leasefile, &st) == 0) 3650d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { 3651d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan time_t now; 3652d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3653d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* Offset lease times and check expiry */ 3654d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan now = time(NULL); 3655d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (now == -1 || 3656d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan (time_t)state->lease.leasetime < now - st.st_mtime) 3657d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { 3658d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_DEBUG, 3659d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%s: discarding expired lease", ifp->name); 3660d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan free(state->offer); 3661d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->offer = NULL; 3662d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->lease.addr.s_addr = 0; 3663d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* Technically we should discard the lease 3664d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * as it's expired, just as DHCPv6 addresses 3665d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * would be by the kernel. 3666d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * However, this may violate POLA so 3667d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * we currently leave it be. 3668d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * If we get a totally different lease from 3669d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * the DHCP server we'll drop it anyway, as 3670d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * we will on any other event which would 3671d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * trigger a lease drop. 3672d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * This should only happen if dhcpcd stops 3673d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * running and the lease expires before 3674d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * dhcpcd starts again. */ 3675d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#if 0 3676d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state->new) 3677d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_drop(ifp, "EXPIRE"); 3678d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif 3679d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } else { 3680d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan l = (uint32_t)(now - st.st_mtime); 3681d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->lease.leasetime -= l; 3682d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->lease.renewaltime -= l; 3683d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->lease.rebindtime -= l; 3684d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3685d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3686d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3687d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3688d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (!(ifo->options & DHCPCD_DHCP)) { 3689d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifo->options & DHCPCD_IPV4LL) { 3690d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state->offer && state->offer->cookie != 0) { 3691d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan free(state->offer); 3692d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->offer = NULL; 3693d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3694d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ipv4ll_start(ifp); 3695d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3696d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 3697d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3698d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3699d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state->offer == NULL || state->offer->cookie == 0) 3700d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_discover(ifp); 3701d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan else 3702d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_reboot(ifp); 3703d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 3704d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3705d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanvoid 3706d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_start(struct interface *ifp) 3707d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 3708d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct timespec tv; 3709d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3710d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (!(ifp->options->options & DHCPCD_IPV4)) 3711d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 3712d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3713d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* No point in delaying a static configuration */ 3714d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan tv.tv_sec = DHCP_MIN_DELAY; 3715d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan tv.tv_nsec = (suseconds_t)arc4random_uniform( 3716d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan (DHCP_MAX_DELAY - DHCP_MIN_DELAY) * NSEC_PER_SEC); 3717d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan timespecnorm(&tv); 3718d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_DEBUG, 3719d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%s: delaying IPv4 for %0.1f seconds", 3720d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->name, timespec_to_double(&tv)); 3721d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3722d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan eloop_timeout_add_tv(ifp->ctx->eloop, &tv, dhcp_start1, ifp); 3723d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 3724d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3725d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanvoid 3726d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_handleifa(int cmd, struct interface *ifp, 3727d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan const struct in_addr *addr, 3728d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan const struct in_addr *net, 3729d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan const struct in_addr *dst, 3730d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan __unused int flags) 3731d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 3732d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct dhcp_state *state; 3733d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct if_options *ifo; 3734d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan uint8_t i; 3735d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3736d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state = D_STATE(ifp); 3737d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state == NULL) 3738d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 3739d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3740d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (cmd == RTM_DELADDR) { 3741d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state->addr.s_addr == addr->s_addr && 3742d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->net.s_addr == net->s_addr) 3743d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { 3744d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(ifp->ctx, LOG_INFO, 3745d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%s: removing IP address %s/%d", 3746d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifp->name, inet_ntoa(state->addr), 3747d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan inet_ntocidr(state->net)); 3748d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_drop(ifp, "EXPIRE"); 3749d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3750d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 3751d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3752d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3753d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (cmd != RTM_NEWADDR) 3754d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 3755d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3756d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifo = ifp->options; 3757d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifo->options & DHCPCD_INFORM) { 3758d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state->state != DHS_INFORM) 3759d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_inform(ifp); 3760d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 3761d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3762d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3763d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (!(ifo->options & DHCPCD_STATIC)) 3764d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 3765d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifo->req_addr.s_addr != INADDR_ANY) 3766d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 3767d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 3768d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan free(state->old); 3769d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->old = state->new; 3770d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->new = dhcp_message_new(addr, net); 3771d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (state->new == NULL) 3772d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 3773d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->dst.s_addr = dst ? dst->s_addr : INADDR_ANY; 3774d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (dst) { 3775d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan for (i = 1; i < 255; i++) 3776d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (i != DHO_ROUTER && has_option_mask(ifo->dstmask,i)) 3777d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_message_add_addr(state->new, i, *dst); 3778d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3779d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->reason = "STATIC"; 3780d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ipv4_buildroutes(ifp->ctx); 3781d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan script_runreason(ifp, state->reason); 3782d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifo->options & DHCPCD_INFORM) { 3783d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->state = DHS_INFORM; 3784d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->xid = dhcp_xid(ifp); 3785d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->lease.server.s_addr = dst ? dst->s_addr : INADDR_ANY; 3786d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->addr = *addr; 3787d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan state->net = *net; 3788d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan dhcp_inform(ifp); 3789d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 3790d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 3791