From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: passt.top; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: passt.top; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=R8eRrQZj; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by passt.top (Postfix) with ESMTPS id DD5725A0265 for ; Thu, 28 May 2026 21:01:52 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779994911; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=qopy2dLQegctBYHDpOYqtPONitMMJdZ+10xWHQZX37Q=; b=R8eRrQZjEDATGwVRSALdby7O1wc0q60rclMPYDR6X6uXsXM1Cl1N+cXMy4cfPoDLIt1kBO 1HfPmS/yY/vneZ8FYx6eIAr6/emoXn+HdhheKORBzh9l/ARwPY7meMf/WyBMub2ZYt1W5E cobeM71oI6IBlPcTBJ2eUolxPL0KGrY= Received: from mail-wr1-f69.google.com (mail-wr1-f69.google.com [209.85.221.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-360-Dfbi81fgOjyKS_ZT_476cA-1; Thu, 28 May 2026 15:01:50 -0400 X-MC-Unique: Dfbi81fgOjyKS_ZT_476cA-1 X-Mimecast-MFC-AGG-ID: Dfbi81fgOjyKS_ZT_476cA_1779994909 Received: by mail-wr1-f69.google.com with SMTP id ffacd0b85a97d-45e7c7289c3so10298263f8f.1 for ; Thu, 28 May 2026 12:01:49 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779994909; x=1780599709; h=date:content-transfer-encoding:mime-version:organization:references :in-reply-to:message-id:subject:cc:to:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=rcY5R/bTplyKEVPzle/fIsEnqF9Zic9rYo5KUXEQqUw=; b=g9X97JzG6dZZWIDdcWNfrMLpuXHnphmMj9pn0qD5XGxmJ2MKsXMqguruqXfGw5a7hZ PNIv05eDOc9oxhukj/mmQqKoSYI8UGWL8zfXyvtBOshQSRIniohMz6xtFzvCWEi13MOR lEKiYa2vzbA7l6o9R1QDRmdf4gNShD1jb8L2tnQrU5t1S+AOwPvJTmk2V2KXKF0d2Xrp jGe9QahrPw8g47NYgASxlWzDACM8V+ZgjLr9xftBhQ+Eu9v87WhM9OP3izUwb0pmnKXg kMsZEurAZYF81hwEjNL/EbryG6IyeVVhKly6F27scVDf6nTa2781UMrJPFg5tNORxI8b HI4g== X-Gm-Message-State: AOJu0Yy+xmShEJA/oMZSU5lR4gCU9VLL3/LE6mijpoKEdzoWCk4SxjKq p5PvMP3tJNTE2D2Q51CrpwCDPKCdWRXm5DWu9kigi0eOzomamCVB2ettkJqiR+j5AFAhJD0PPCk RN+AxiYCT+nYr6CRfvJHgjZG+5PFjthV9z6NdyOPaj1cPNQIOnyDuQg== X-Gm-Gg: Acq92OFlSGkUc1PFxI4u9g2jGDOPa1f0MBTBZ69fG5KaWv9zbWds8AWyYj8I1rtSoyK nrtSYvG1kVDnXeFC/1NVB/epabDU7aXK+f2F3zg8mjZwwXgIlvAggOb0t+2fZs7qOlRFn3mBXLn 2KNBJud4PhpxoEt415Qi4PORtm/9cRFrx5+Xv+Xl/fGQqzSxX49+nVK7Ew1psO9qPbtoV4fn1aN 7JANW9Tk+hp3h3zBlPAUuP/Hw8Vh7aEPiILBXD4S68YLSIzyL47linTX4j9anhQGymD3Ha0pv3W D8X8LgkwLYYLjwegOoa+qgnnPbv+WAO28ZdlNRXHh9IlBCFIRiXKPliRLBbcpOGx7rfmsP91jiu ReMwYuVfTkYu+CEFBZmsWwXwKk5TZQzDq0S0GocljyWHkpHE6FCSMNv9nADFT X-Received: by 2002:adf:e00c:0:10b0:45a:5392:3a19 with SMTP id ffacd0b85a97d-45eeba73216mr3195894f8f.16.1779994908535; Thu, 28 May 2026 12:01:48 -0700 (PDT) X-Received: by 2002:adf:e00c:0:10b0:45a:5392:3a19 with SMTP id ffacd0b85a97d-45eeba73216mr3195844f8f.16.1779994907967; Thu, 28 May 2026 12:01:47 -0700 (PDT) Received: from maya.myfinge.rs (ifcgrfdd.trafficplex.cloud. [176.103.220.4]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-45eec25e7c4sm3916471f8f.37.2026.05.28.12.01.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 28 May 2026 12:01:47 -0700 (PDT) From: Stefano Brivio To: Anshu Kumari Subject: Re: [PATCH v2 3/6] dhcp: Add option type table and value parser Message-ID: <20260528210141.0e747a03@elisabeth> In-Reply-To: <20260526123115.1226166-4-anskuma@redhat.com> References: <20260526123115.1226166-1-anskuma@redhat.com> <20260526123115.1226166-4-anskuma@redhat.com> Organization: Red Hat X-Mailer: Claws Mail 4.2.0 (GTK 3.24.49; x86_64-pc-linux-gnu) MIME-Version: 1.0 Date: Thu, 28 May 2026 21:01:46 +0200 (CEST) X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: xo0L05d6xgiU5XA94X3KBVX8iGKvzU30QKsYSh3vFOw_1779994909 X-Mimecast-Originator: redhat.com Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Message-ID-Hash: BW2A4HT3FXMUIPCOIZF4TKRNKF4ZGZDA X-Message-ID-Hash: BW2A4HT3FXMUIPCOIZF4TKRNKF4ZGZDA X-MailFrom: sbrivio@redhat.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: passt-dev@passt.top, jmaloy@redhat.com, lvivier@redhat.com, david@gibson.dropbear.id.au X-Mailman-Version: 3.3.8 Precedence: list List-Id: Development discussion and patches for passt Archived-At: Archived-At: List-Archive: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: On Tue, 26 May 2026 18:01:10 +0530 Anshu Kumari wrote: > Add an RFC 2132 type lookup table mapping DHCP option codes to their > expected value formats, and a dhcp_opt_parse() function that converts > CLI string values into their binary wire representation. >=20 > Wire dhcp_opt_parse() into the --dhcp-opt handler so that values are > validated and encoded at configuration time. >=20 > Link: https://bugs.passt.top/show_bug.cgi?id=3D192 > Signed-off-by: Anshu Kumari > --- > v2: > - Replaced struct lookup table + dhcp_opt_type_lookup() function with f= lat dhcp_opt_types[256] array indexed by code. > - Consolidated DHCP_OPT_UINT8/UINT16/UINT32 into single DHCP_OPT_INTEGE= R with dhcp_opt_int_width[256] table. > - Dropped DHCP_OPT_ROUTES / option 121 entirely. > - Added kerneldoc for enum dhcp_opt_type values. > - Removed curly braces from switch cases, declarations before switch. > - Added newlines before return statements. > - Changed IP list delimiter from space to comma (--dhcp-opt 6,1.1.1.1,8= .8.8.8). > - Defined DHCP_OPT_PARSE_BUF constant for bare 1024. > - Added len and val[255] fields to struct here (moved from patch=C2=A01= ). > - Added kerneldoc for @custom_opts.len and @custom_opts.val. > - Wired dhcp_opt_parse() into case 32 (--dhcp-boot) to populate val/len= . > --- > conf.c | 16 ++++++ > dhcp.c | 148 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > dhcp.h | 17 +++++++ > passt.h | 4 ++ > 4 files changed, 185 insertions(+) >=20 > diff --git a/conf.c b/conf.c > index ae8ee26..3a5f45d 100644 > --- a/conf.c > +++ b/conf.c > @@ -1266,6 +1266,7 @@ void conf(struct ctx *c, int argc, char **argv) > =09char *end; > =09uid_t uid; > =09gid_t gid; > +=09int len; > =09 > =20 > =09if (c->mode =3D=3D MODE_PASTA) > @@ -1482,7 +1483,14 @@ void conf(struct ctx *c, int argc, char **argv) > =09=09=09=09die("Too many DHCP options (max %d)", > =09=09=09=09 MAX_CUSTOM_DHCP_OPTS); > =20 > +=09=09=09ret =3D dhcp_opt_parse(67, optarg, > +=09=09=09=09=09 c->custom_opts[c->custom_opts_count].val, > +=09=09=09=09=09 sizeof(c->custom_opts[0].val)); > +=09=09=09if (ret < 0) > +=09=09=09=09die("Invalid boot file value: %s", optarg); > + > =09=09=09c->custom_opts[c->custom_opts_count].code =3D 67; > +=09=09=09c->custom_opts[c->custom_opts_count].len =3D ret; > =09=09=09if (snprintf_check(c->custom_opts[c->custom_opts_count].str, > =09=09=09=09=09 sizeof(c->custom_opts[0].str), > =09=09=09=09=09 "%s", optarg)) > @@ -1503,7 +1511,15 @@ void conf(struct ctx *c, int argc, char **argv) > =09=09=09=09die("Too many --dhcp-opt entries (max %d)", > =09=09=09=09 MAX_CUSTOM_DHCP_OPTS); > =20 > +=09=09=09len =3D dhcp_opt_parse(optcode, comma + 1, > +=09=09=09=09=09 c->custom_opts[c->custom_opts_count].val, > +=09=09=09=09=09 sizeof(c->custom_opts[0].val)); > +=09=09=09if (len < 0) > +=09=09=09=09die("Invalid value for DHCP option %lu: %s", > +=09=09=09=09 optcode, comma + 1); > + > =09=09=09c->custom_opts[c->custom_opts_count].code =3D optcode; > +=09=09=09c->custom_opts[c->custom_opts_count].len =3D len; > =09=09=09if (snprintf_check(c->custom_opts[c->custom_opts_count].str, > =09=09=09=09=09 sizeof(c->custom_opts[0].str), > =09=09=09=09=09 "%s", comma + 1)) > diff --git a/dhcp.c b/dhcp.c > index 1ff8cba..e1c95ad 100644 > --- a/dhcp.c > +++ b/dhcp.c > @@ -33,6 +33,154 @@ > #include "log.h" > #include "dhcp.h" > =20 > +/** > + * dhcp_opt_types - Maps option code to RFC 2132 value type, indexed by = code > + */ > +static const enum dhcp_opt_type dhcp_opt_types[256] =3D { > +=09[1] =3D DHCP_OPT_IPV4,=09=09/* Subnet Mask */ > +=09[2] =3D DHCP_OPT_INTEGER,=09/* Time Offset */ > +=09[3] =3D DHCP_OPT_IPV4_LIST,=09/* Router */ > +=09[4] =3D DHCP_OPT_IPV4_LIST,=09/* Time Server */ > +=09[5] =3D DHCP_OPT_IPV4_LIST,=09/* Name Server */ > +=09[6] =3D DHCP_OPT_IPV4_LIST,=09/* Domain Name Server */ > +=09[7] =3D DHCP_OPT_IPV4_LIST,=09/* Log Server */ > +=09[8] =3D DHCP_OPT_IPV4_LIST,=09/* Cookie Server */ > +=09[9] =3D DHCP_OPT_IPV4_LIST,=09/* LPR Server */ > +=09[10] =3D DHCP_OPT_IPV4_LIST,=09/* Impress Server */ > +=09[11] =3D DHCP_OPT_IPV4_LIST,=09/* Resource Location Server */ > +=09[12] =3D DHCP_OPT_STR,=09=09/* Host Name */ > +=09[13] =3D DHCP_OPT_INTEGER,=09/* Boot File Size */ > +=09[15] =3D DHCP_OPT_STR,=09=09/* Domain Name */ > +=09[16] =3D DHCP_OPT_IPV4,=09=09/* Swap Server */ > +=09[17] =3D DHCP_OPT_STR,=09=09/* Root Path */ > +=09[19] =3D DHCP_OPT_INTEGER,=09/* IP Forwarding */ > +=09[23] =3D DHCP_OPT_INTEGER,=09/* Default IP TTL */ > +=09[26] =3D DHCP_OPT_INTEGER,=09/* Interface MTU */ > +=09[28] =3D DHCP_OPT_IPV4,=09=09/* Broadcast Address */ > +=09[33] =3D DHCP_OPT_IPV4_LIST,=09/* Static Routes */ > +=09[37] =3D DHCP_OPT_INTEGER,=09/* TCP Default TTL */ > +=09[38] =3D DHCP_OPT_INTEGER,=09/* TCP Keepalive Interval */ > +=09[40] =3D DHCP_OPT_STR,=09=09/* NIS Domain Name */ > +=09[41] =3D DHCP_OPT_IPV4_LIST,=09/* NIS Servers */ > +=09[42] =3D DHCP_OPT_IPV4_LIST,=09/* NTP Servers */ > +=09[44] =3D DHCP_OPT_IPV4_LIST,=09/* NetBIOS Name Server */ > +=09[50] =3D DHCP_OPT_IPV4,=09=09/* Requested IP Address */ > +=09[51] =3D DHCP_OPT_INTEGER,=09/* IP Address Lease Time */ > +=09[53] =3D DHCP_OPT_INTEGER,=09/* DHCP Message Type */ > +=09[54] =3D DHCP_OPT_IPV4,=09=09/* Server Identifier */ > +=09[55] =3D DHCP_OPT_STR,=09=09/* Parameter Request List */ > +=09[57] =3D DHCP_OPT_INTEGER,=09/* Max DHCP Message Size */ > +=09[58] =3D DHCP_OPT_INTEGER,=09/* Renewal (T1) Time */ > +=09[59] =3D DHCP_OPT_INTEGER,=09/* Rebinding (T2) Time */ > +=09[60] =3D DHCP_OPT_STR,=09=09/* Vendor Class Identifier */ > +=09[61] =3D DHCP_OPT_STR,=09=09/* Client Identifier */ > +=09[66] =3D DHCP_OPT_STR,=09=09/* TFTP Server Name */ > +=09[67] =3D DHCP_OPT_STR,=09=09/* Bootfile Name */ > +=09[119] =3D DHCP_OPT_STR,=09=09/* Domain Search List */ Nit: a bit easier on eyes if they are *all* aligned (with one extra space), that is: =09[9] =3D DHCP_OPT_IPV4_LIST,=09/* LPR Server */ =09[...] =09[67] =3D DHCP_OPT_STR,=09=09/* Bootfile Name */ =09[...] =09[119] =3D DHCP_OPT_STR,=09=09/* Domain Search List */ =09[...] > +=09[252] =3D DHCP_OPT_STR,=09=09/* WPAD URL */ > +}; > + > +/** > + * dhcp_opt_int_width - Integer width in bytes for INTEGER-typed options > + */ > +static const uint8_t dhcp_opt_int_width[256] =3D { > +=09[2] =3D 4,=09/* Time Offset */ > +=09[13] =3D 2,=09/* Boot File Size */ > +=09[19] =3D 1,=09/* IP Forwarding */ > +=09[23] =3D 1,=09/* Default IP TTL */ > +=09[26] =3D 2,=09/* Interface MTU */ > +=09[37] =3D 1,=09/* TCP Default TTL */ > +=09[38] =3D 4,=09/* TCP Keepalive Interval */ > +=09[51] =3D 4,=09/* IP Address Lease Time */ > +=09[53] =3D 1,=09/* DHCP Message Type */ > +=09[57] =3D 2,=09/* Max DHCP Message Size */ > +=09[58] =3D 4,=09/* Renewal (T1) Time */ > +=09[59] =3D 4,=09/* Rebinding (T2) Time */ > +}; > + > +#define DHCP_OPT_PARSE_BUF=091024 > + > +/** > + * dhcp_opt_parse() - Parse a DHCP option value > + * @code:=09DHCP option code > + * @str:=09DHCP Value string from command line > + * @buf:=09Output buffer > + * @buf_len:=09Size of output buffer > + * > + * Return: number of bytes written to @buf, or -1 on error > + */ > +int dhcp_opt_parse(uint8_t code, const char *str, uint8_t *buf, size_t b= uf_len) > +{ > +=09enum dhcp_opt_type type =3D dhcp_opt_types[code]; > +=09char tmp[DHCP_OPT_PARSE_BUF]; > +=09char *tok, *saveptr, *end; > +=09struct in_addr addr; > +=09unsigned long val; > +=09unsigned int i; > +=09uint8_t width; > +=09size_t slen; > +=09int len; > + > +=09switch (type) { > +=09case DHCP_OPT_NONE: > +=09=09die("Unsupported DHCP option: %u," > +=09=09 " see passt(1) for supported codes", code); > +=09case DHCP_OPT_IPV4: > +=09=09if (inet_pton(AF_INET, str, &addr) !=3D 1) > +=09=09=09return -1; > + > +=09=09if (buf_len < sizeof(addr)) > +=09=09=09return -1; > + > +=09=09memcpy(buf, &addr, sizeof(addr)); > + > +=09=09return sizeof(addr); > +=09case DHCP_OPT_IPV4_LIST: > +=09=09len =3D 0; > + > +=09=09if (snprintf_check(tmp, sizeof(tmp), "%s", str)) > +=09=09=09return -1; > + > +=09=09for (tok =3D strtok_r(tmp, ",", &saveptr); tok; > +=09=09 tok =3D strtok_r(NULL, ",", &saveptr)) { > +=09=09=09if (inet_pton(AF_INET, tok, &addr) !=3D 1) > +=09=09=09=09return -1; > + > +=09=09=09if (len + (int)sizeof(addr) > (int)buf_len) > +=09=09=09=09return -1; > + > +=09=09=09memcpy(buf + len, &addr, sizeof(addr)); > +=09=09=09len +=3D sizeof(addr); > +=09=09} > +=09=09return len; > +=09case DHCP_OPT_INTEGER: > +=09=09width =3D dhcp_opt_int_width[code]; > +=09=09val =3D strtoul(str, &end, 0); > + > +=09=09if (*end || buf_len < width) > +=09=09=09return -1; > + > +=09=09if (width < 4 && val >=3D (1UL << (width * 8))) > +=09=09=09return -1; > + > +=09=09for (i =3D 0; i < width; i++) > +=09=09=09buf[i] =3D (val >> ((width - 1 - i) * 8)) & 0xff; > + > +=09=09return width; > +=09case DHCP_OPT_STR: > +=09=09slen =3D strlen(str); > + > +=09=09if (!slen || slen >=3D buf_len) > +=09=09=09return -1; > + > +=09=09strncpy((char *)buf, str, buf_len); > + > +=09=09return slen; > +=09} > + > +=09return -1; > +} > + > /** > * struct opt - DHCP option > * @sent:=09Convenience flag, set while filling replies > diff --git a/dhcp.h b/dhcp.h > index cd50c99..3da571c 100644 > --- a/dhcp.h > +++ b/dhcp.h > @@ -6,7 +6,24 @@ > #ifndef DHCP_H > #define DHCP_H > =20 > +/** > + * enum dhcp_opt_type - DHCP option value types per RFC 2132 > + * @DHCP_OPT_NONE:=09Unsupported or unknown option > + * @DHCP_OPT_STR:=09Variable-length string > + * @DHCP_OPT_IPV4:=09Single IPv4 address > + * @DHCP_OPT_IPV4_LIST:Multiple IPv4 addresses, comma-separated Missing tab between @DHCP_OPT_IPV4_LIST and Multiple: * @DHCP_OPT_IPV4_LIST:=09Multiple IPv4 addresses, comma-separated > + * @DHCP_OPT_INTEGER:=09Unsigned integer (1, 2, or 4 bytes) > + */ > +enum dhcp_opt_type { > +=09DHCP_OPT_NONE, > +=09DHCP_OPT_STR, > +=09DHCP_OPT_IPV4, > +=09DHCP_OPT_IPV4_LIST, > +=09DHCP_OPT_INTEGER, > +}; > + > int dhcp(const struct ctx *c, struct iov_tail *data); > void dhcp_init(void); > +int dhcp_opt_parse(uint8_t code, const char *str, uint8_t *buf, size_t b= uf_len); > =20 > #endif /* DHCP_H */ > diff --git a/passt.h b/passt.h > index 3a0816f..751fee3 100644 > --- a/passt.h > +++ b/passt.h > @@ -184,6 +184,8 @@ struct ip6_ctx { > * @fqdn:=09=09Guest FQDN > * @custom_opts:=09User-specified DHCP options from --dhcp-opt > * @custom_opts.code:=09DHCP option code > + * @custom_opts.len:=09Length of binary value in @val > + * @custom_opts.val:=09Binary-encoded option value > * @custom_opts.str:=09Original string value from command line > * @custom_opts_count:=09Number of entries in @custom_opts > * @ifi6:=09=09Template interface for IPv6, -1: none, 0: IPv6 disabled > @@ -271,6 +273,8 @@ struct ctx { > =20 > =09struct { > =09=09uint8_t code; > +=09=09uint8_t len; > +=09=09uint8_t val[255]; > =09=09char str[256]; > =09} custom_opts[MAX_CUSTOM_DHCP_OPTS]; > =09int custom_opts_count; --=20 Stefano