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=VLf2xvyB; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by passt.top (Postfix) with ESMTPS id 650D45A0265 for ; Thu, 28 May 2026 07:39:24 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779946763; 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: in-reply-to:in-reply-to:references:references; bh=ZhP2CEIieqmGCTcil/1GMaXt/YTfVlAsF6qITd1/FhQ=; b=VLf2xvyB4gFg3NHXPuRKbguCImUN4EbM8gm0OW5pgCHv8r1/vYyjfpTMC/3+HuZDz2SbZM fKX6yNhojG7Yg0WOfyn6k8Xgz9fOTFdYcppeTq9fnR4dEz3aKg0F1WdFBbPqYfFXdq6pPg 9BVvZA+8HoHPXiey5WGruoHf5eE5StU= Received: from mail-lf1-f70.google.com (mail-lf1-f70.google.com [209.85.167.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-121-wGW4JsOWONycfy-DjNVDbw-1; Thu, 28 May 2026 01:39:20 -0400 X-MC-Unique: wGW4JsOWONycfy-DjNVDbw-1 X-Mimecast-MFC-AGG-ID: wGW4JsOWONycfy-DjNVDbw_1779946759 Received: by mail-lf1-f70.google.com with SMTP id 2adb3069b0e04-5a86e837da3so7386470e87.0 for ; Wed, 27 May 2026 22:39:20 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779946759; x=1780551559; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=ZhP2CEIieqmGCTcil/1GMaXt/YTfVlAsF6qITd1/FhQ=; b=fV1VvjBFpspk6zFCNGqgL3T/t7zQhpkG/YArV1cuFR+rEpMwVerIH0TOPP/+1hCdyS tofeAtYdvIPFikb1CCeoEXrINfqTK9u2ROBL9hnIupjvrW3M48Eeb8/Dkysx5jjf32Sm edbgPRzOPeETwDUJQNZgTTZ66iUeEtRlOOH7Z8bySuu2Lm+/2nkyAP70EvlODidb7kaL F61CPuDpd7rYqlv3DivCJLH5btMaRwBHBGAOTkMMu5/FPVXOP/BIGMECzKqhGbt5QBw/ QbsLC9HxPETBOr2qRfwN+qyPMf3FgoVrXFwGyAQYGxVS7PM51vNn5iJTYGetaSNvDTtY ta0g== X-Gm-Message-State: AOJu0YxuX1LBGytKtWHQySU5bxkCU0G/dbVQgNgkuqTEKzLTxsgMlWsC gCq+9TbdPJOBlurmk3oyBrHEFEqfWsPDnD9kC5S3lspvaTtHfQmExvJipHRHMuKb8mYoYfD5cSG lAe4wE4zK4YKMwqDt4LxPDXOL1igWzcbQFg9C2KfSdxsbOdugj6cJXsWI+D/+qDSvfMqXMP1IOA ZG5BKAh/Mm/zDhbyNoACIsBoZnmMwI X-Gm-Gg: Acq92OGnpoUzf8pN/iN1MdDkzdaeKo52G4t6vTpghj75jGRp08hQfLGpEohjfeQfoSb 8R6r49oCQG5TxLoEyDoeemljz+3lThVhjdovs0yQK+0Pz6GHZ9amZbgF9a/PYgM+/ubPN4JOpZE a5GOA4Vfxxi16fyElAdNlZyCQVnpYFXtd3aGS4rIwkrJVeceK+OzWBBsCTpyYc9UCeDq+gXoGky TSepsAbyNYuP0w8EMqR3ZjZpWw0HFEMAdk3XopTqtJs2ilk1Q== X-Received: by 2002:a05:6512:3047:b0:5aa:b6a:7a8b with SMTP id 2adb3069b0e04-5aa32396e68mr8400108e87.42.1779946759063; Wed, 27 May 2026 22:39:19 -0700 (PDT) X-Received: by 2002:a05:6512:3047:b0:5aa:b6a:7a8b with SMTP id 2adb3069b0e04-5aa32396e68mr8400101e87.42.1779946758449; Wed, 27 May 2026 22:39:18 -0700 (PDT) MIME-Version: 1.0 References: <20260526123115.1226166-1-anskuma@redhat.com> <20260526123115.1226166-4-anskuma@redhat.com> <46780f40-afb9-4a63-895c-9564dc0d6abe@redhat.com> In-Reply-To: <46780f40-afb9-4a63-895c-9564dc0d6abe@redhat.com> From: Anshu Kumari Date: Thu, 28 May 2026 11:09:06 +0530 X-Gm-Features: AVHnY4KIcjZxCHGstNqiV0kEJG-0Q1L0Vc4-9tFnhKBxEL5mP52TXH9PsZV-95g Message-ID: Subject: Re: [PATCH v2 3/6] dhcp: Add option type table and value parser To: Laurent Vivier X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: DMKoHJToxoF7hXlJGEy501UcIfQKB8-DK4Ib9SAsmT4_1779946759 X-Mimecast-Originator: redhat.com Content-Type: multipart/alternative; boundary="00000000000041b8fc0652da26d8" Message-ID-Hash: ZBARXGJUAMT77KWU4AGTPODNVY7FZ6QJ X-Message-ID-Hash: ZBARXGJUAMT77KWU4AGTPODNVY7FZ6QJ X-MailFrom: anskuma@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, sbrivio@redhat.com, jmaloy@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: --00000000000041b8fc0652da26d8 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Tue, May 26, 2026 at 9:35=E2=80=AFPM Laurent Vivier = wrote: > On 5/26/26 14:31, 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. > > > > Wire dhcp_opt_parse() into the --dhcp-opt handler so that values are > > validated and encoded at configuration time. > > > > 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 wit= h > flat dhcp_opt_types[256] array indexed by code. > > - Consolidated DHCP_OPT_UINT8/UINT16/UINT32 into single > DHCP_OPT_INTEGER 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 1). > > - 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(+) > > > > 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) > > char *end; > > uid_t uid; > > gid_t gid; > > + int len; > > I think you don't need to introduce len for --dhcp-opt as you already use > ret for --dhcp-boot > > > > > > if (c->mode =3D=3D MODE_PASTA) > > @@ -1482,7 +1483,14 @@ void conf(struct ctx *c, int argc, char **argv) > > die("Too many DHCP options (max %d)", > > MAX_CUSTOM_DHCP_OPTS); > > > > + ret =3D dhcp_opt_parse(67, optarg, > > + > c->custom_opts[c->custom_opts_count].val, > > + > sizeof(c->custom_opts[0].val)); > > + if (ret < 0) > > + die("Invalid boot file value: %s", optarg= ); > > + > > c->custom_opts[c->custom_opts_count].code =3D 67; > > + c->custom_opts[c->custom_opts_count].len =3D ret; > > if > (snprintf_check(c->custom_opts[c->custom_opts_count].str, > > sizeof(c->custom_opts[0].str), > > "%s", optarg)) > > @@ -1503,7 +1511,15 @@ void conf(struct ctx *c, int argc, char **argv) > > die("Too many --dhcp-opt entries (max %d)= ", > > MAX_CUSTOM_DHCP_OPTS); > > > > + len =3D dhcp_opt_parse(optcode, comma + 1, > > + > c->custom_opts[c->custom_opts_count].val, > > + > sizeof(c->custom_opts[0].val)); > > you can use "ret" here too > > > + if (len < 0) > > + die("Invalid value for DHCP option %lu: > %s", > > + optcode, comma + 1); > > + > > c->custom_opts[c->custom_opts_count].code =3D > optcode; > > + c->custom_opts[c->custom_opts_count].len =3D len; > > if > (snprintf_check(c->custom_opts[c->custom_opts_count].str, > > sizeof(c->custom_opts[0].str), > > "%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" > > > > +/** > > + * dhcp_opt_types - Maps option code to RFC 2132 value type, indexed b= y > code > > + */ > > +static const enum dhcp_opt_type dhcp_opt_types[256] =3D { > > + [1] =3D DHCP_OPT_IPV4, /* Subnet Mask */ > > + [2] =3D DHCP_OPT_INTEGER, /* Time Offset */ > > + [3] =3D DHCP_OPT_IPV4_LIST, /* Router */ > > + [4] =3D DHCP_OPT_IPV4_LIST, /* Time Server */ > > + [5] =3D DHCP_OPT_IPV4_LIST, /* Name Server */ > > + [6] =3D DHCP_OPT_IPV4_LIST, /* Domain Name Server */ > > + [7] =3D DHCP_OPT_IPV4_LIST, /* Log Server */ > > + [8] =3D DHCP_OPT_IPV4_LIST, /* Cookie Server */ > > + [9] =3D DHCP_OPT_IPV4_LIST, /* LPR Server */ > > + [10] =3D DHCP_OPT_IPV4_LIST, /* Impress Server */ > > + [11] =3D DHCP_OPT_IPV4_LIST, /* Resource Location Server */ > > + [12] =3D DHCP_OPT_STR, /* Host Name */ > > + [13] =3D DHCP_OPT_INTEGER, /* Boot File Size */ > > + [15] =3D DHCP_OPT_STR, /* Domain Name */ > > + [16] =3D DHCP_OPT_IPV4, /* Swap Server */ > > + [17] =3D DHCP_OPT_STR, /* Root Path */ > > + [19] =3D DHCP_OPT_INTEGER, /* IP Forwarding */ > > + [23] =3D DHCP_OPT_INTEGER, /* Default IP TTL */ > > + [26] =3D DHCP_OPT_INTEGER, /* Interface MTU */ > > + [28] =3D DHCP_OPT_IPV4, /* Broadcast Address */ > > + [33] =3D DHCP_OPT_IPV4_LIST, /* Static Routes */ > > + [37] =3D DHCP_OPT_INTEGER, /* TCP Default TTL */ > > + [38] =3D DHCP_OPT_INTEGER, /* TCP Keepalive Interval */ > > + [40] =3D DHCP_OPT_STR, /* NIS Domain Name */ > > + [41] =3D DHCP_OPT_IPV4_LIST, /* NIS Servers */ > > + [42] =3D DHCP_OPT_IPV4_LIST, /* NTP Servers */ > > + [44] =3D DHCP_OPT_IPV4_LIST, /* NetBIOS Name Server */ > > + [50] =3D DHCP_OPT_IPV4, /* Requested IP Address */ > > + [51] =3D DHCP_OPT_INTEGER, /* IP Address Lease Time */ > > + [53] =3D DHCP_OPT_INTEGER, /* DHCP Message Type */ > > + [54] =3D DHCP_OPT_IPV4, /* Server Identifier */ > > + [55] =3D DHCP_OPT_STR, /* Parameter Request List */ > > This is a client option, I don't think we need to manage it. > > > + [57] =3D DHCP_OPT_INTEGER, /* Max DHCP Message Size */ > > + [58] =3D DHCP_OPT_INTEGER, /* Renewal (T1) Time */ > > + [59] =3D DHCP_OPT_INTEGER, /* Rebinding (T2) Time */ > > + [60] =3D DHCP_OPT_STR, /* Vendor Class Identifier */ > > + [61] =3D DHCP_OPT_STR, /* Client Identifier */ > > This is also a client option. > > > + [66] =3D DHCP_OPT_STR, /* TFTP Server Name */ > > + [67] =3D DHCP_OPT_STR, /* Bootfile Name */ > > + [119] =3D DHCP_OPT_STR, /* Domain Search List */ > > This is not really a string as this uses the message compression describe= d > in RFC 1035, > 4.1.4. (See also 3. Example in rfc3397). I'm not sure we can encode this > manually on the > command line. And RFC 3396 defines how to encode search string for more > than 255 > characters length > > > + [252] =3D DHCP_OPT_STR, /* WPAD URL */ > > +}; > > + > > +/** > > + * dhcp_opt_int_width - Integer width in bytes for INTEGER-typed optio= ns > > + */ > > +static const uint8_t dhcp_opt_int_width[256] =3D { > > + [2] =3D 4, /* Time Offset */ > > + [13] =3D 2, /* Boot File Size */ > > + [19] =3D 1, /* IP Forwarding */ > > + [23] =3D 1, /* Default IP TTL */ > > + [26] =3D 2, /* Interface MTU */ > > + [37] =3D 1, /* TCP Default TTL */ > > + [38] =3D 4, /* TCP Keepalive Interval */ > > + [51] =3D 4, /* IP Address Lease Time */ > > + [53] =3D 1, /* DHCP Message Type */ > > + [57] =3D 2, /* Max DHCP Message Size */ > > + [58] =3D 4, /* Renewal (T1) Time */ > > + [59] =3D 4, /* Rebinding (T2) Time */ > > +}; > > + > > +#define DHCP_OPT_PARSE_BUF 1024 > > Do we need 1024 bytes, all options are bounded to 256 bytes. > > + > > +/** > > + * dhcp_opt_parse() - Parse a DHCP option value > > + * @code: DHCP option code > > + * @str: DHCP Value string from command line > > + * @buf: Output buffer > > + * @buf_len: Size 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 > buf_len) > > +{ > > + enum dhcp_opt_type type =3D dhcp_opt_types[code]; > > + char tmp[DHCP_OPT_PARSE_BUF]; > > + char *tok, *saveptr, *end; > > + struct in_addr addr; > > + unsigned long val; > > + unsigned int i; > > + uint8_t width; > > + size_t slen; > > + int len; > > + > > + switch (type) { > > + case DHCP_OPT_NONE: > > + die("Unsupported DHCP option: %u," > > + " see passt(1) for supported codes", code); > > + case DHCP_OPT_IPV4: > > + if (inet_pton(AF_INET, str, &addr) !=3D 1) > > + return -1; > > + > > + if (buf_len < sizeof(addr)) > > + return -1; > > + > > + memcpy(buf, &addr, sizeof(addr)); > > + > > + return sizeof(addr); > > + case DHCP_OPT_IPV4_LIST: > > + len =3D 0; > > + > > + if (snprintf_check(tmp, sizeof(tmp), "%s", str)) > > + return -1; > > + > > + for (tok =3D strtok_r(tmp, ",", &saveptr); tok; > > + tok =3D strtok_r(NULL, ",", &saveptr)) { > > + if (inet_pton(AF_INET, tok, &addr) !=3D 1) > > + return -1; > > + > > + if (len + (int)sizeof(addr) > (int)buf_len) > > + return -1; > > + > > + memcpy(buf + len, &addr, sizeof(addr)); > > + len +=3D sizeof(addr); > > + } > > + return len; > > + case DHCP_OPT_INTEGER: > > + width =3D dhcp_opt_int_width[code]; > > + val =3D strtoul(str, &end, 0); > > + > > + if (*end || buf_len < width) > > + return -1; > > + > > + if (width < 4 && val >=3D (1UL << (width * 8))) > > + return -1; > > + > > + for (i =3D 0; i < width; i++) > > + buf[i] =3D (val >> ((width - 1 - i) * 8)) & 0xff; > > + > > + return width; > > + case DHCP_OPT_STR: > > + slen =3D strlen(str); > > + > > + if (!slen || slen >=3D buf_len) > > + return -1; > > + > > + strncpy((char *)buf, str, buf_len); > > + > > + return slen; > > + } > > + > > + return -1; > > +} > > + > > /** > > * struct opt - DHCP option > > * @sent: Convenience 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 > > > > +/** > > + * enum dhcp_opt_type - DHCP option value types per RFC 2132 > > + * @DHCP_OPT_NONE: Unsupported or unknown option > > + * @DHCP_OPT_STR: Variable-length string > > + * @DHCP_OPT_IPV4: Single IPv4 address > > + * @DHCP_OPT_IPV4_LIST:Multiple IPv4 addresses, comma-separated > > + * @DHCP_OPT_INTEGER: Unsigned integer (1, 2, or 4 bytes) > > + */ > > +enum dhcp_opt_type { > > + DHCP_OPT_NONE, > > + DHCP_OPT_STR, > > + DHCP_OPT_IPV4, > > + DHCP_OPT_IPV4_LIST, > > + DHCP_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 > buf_len); > > > > #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: Guest FQDN > > * @custom_opts: User-specified DHCP options from --dhcp-opt > > * @custom_opts.code: DHCP option code > > + * @custom_opts.len: Length of binary value in @val > > + * @custom_opts.val: Binary-encoded option value > > * @custom_opts.str: Original string value from command line > > * @custom_opts_count: Number of entries in @custom_opts > > * @ifi6: Template interface for IPv6, -1: none, 0: IPv6 > disabled > > @@ -271,6 +273,8 @@ struct ctx { > > > > struct { > > uint8_t code; > > + uint8_t len; > > + uint8_t val[255]; > > char str[256]; > > Why do we need to keep str[] once the value is encoded into val[]? > To print the option value as entered by user. anskuma@anskuma-thinkpadp1gen7:~/Documents/passt$ ./passt -f --dhcp-opt 60,HTTPClient --dhcp-opt 67,http://192.168.1.1:8080/alpine.iso --dhcp-opt 12,testhost --dhcp-opt 15,test.example.com --dhcp-opt 6,8.8.8.8,8.8.4.4 --dhcp-opt 26,1400 --dhcp-opt 42,192.168.1.1 --dhcp-opt 51,360 --dhcp-opt 6,1.1.1.1,9.9.9.9 UNIX domain socket bound at /tmp/passt_1.socket No IPv6 nameserver available for NDP/DHCPv6 Template interface: wlp9s0f0 (IPv4), wlp9s0f0 (IPv6) MAC: host: 9a:55:9a:55:9a:55 NAT to host 127.0.0.1: 192.168.1.1 DHCP: assign: 192.168.1.9 mask: 255.255.255.0 router: 192.168.1.1 *option 60: HTTPClient option 67: http://192.168.1.1:8080/alpine.iso option 12: testhost option 15: test.example.com option 6: 1.1.1.1,9.9.9.9 option 26: 1400 option 42: 192.168.1.1 option 51: 360* > > > } custom_opts[MAX_CUSTOM_DHCP_OPTS]; > > int custom_opts_count; > > Thanks, > Laurent > > --00000000000041b8fc0652da26d8 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable


On Tue, May 26,= 2026 at 9:35=E2=80=AFPM Laurent Vivier <lvivier@redhat.com> wrote:
On 5/26/26 14:31, 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<= br> > CLI string values into their binary wire representation.
>
> Wire dhcp_opt_parse() into the --dhcp-opt handler so that values are > validated and encoded at configuration time.
>
> Link: https://bugs.passt.top/show_bug.cgi?id=3D192<= /a>
> Signed-off-by: Anshu Kumari <
anskuma@redhat.com>
> ---
> v2:
>=C2=A0 =C2=A0 - Replaced struct lookup table + dhcp_opt_type_lookup() f= unction with flat dhcp_opt_types[256] array indexed by code.
>=C2=A0 =C2=A0 - Consolidated DHCP_OPT_UINT8/UINT16/UINT32 into single D= HCP_OPT_INTEGER with dhcp_opt_int_width[256] table.
>=C2=A0 =C2=A0 - Dropped DHCP_OPT_ROUTES / option 121 entirely.
>=C2=A0 =C2=A0 - Added kerneldoc for enum dhcp_opt_type values.
>=C2=A0 =C2=A0 - Removed curly braces from switch cases, declarations be= fore switch.
>=C2=A0 =C2=A0 - Added newlines before return statements.
>=C2=A0 =C2=A0 - Changed IP list delimiter from space to comma (--dhcp-o= pt 6,1.1.1.1,8.8.8.8).
>=C2=A0 =C2=A0 - Defined DHCP_OPT_PARSE_BUF constant for bare 1024.
>=C2=A0 =C2=A0 - Added len and val[255] fields to struct here (moved fro= m patch=C2=A01).
>=C2=A0 =C2=A0 - Added kerneldoc for @custom_opts.len and @custom_opts.v= al.
>=C2=A0 =C2=A0 - Wired dhcp_opt_parse() into case 32 (--dhcp-boot) to po= pulate val/len.
> ---
>=C2=A0 =C2=A0conf.c=C2=A0 |=C2=A0 16 ++++++
>=C2=A0 =C2=A0dhcp.c=C2=A0 | 148 +++++++++++++++++++++++++++++++++++++++= +++++++++++++++++
>=C2=A0 =C2=A0dhcp.h=C2=A0 |=C2=A0 17 +++++++
>=C2=A0 =C2=A0passt.h |=C2=A0 =C2=A04 ++
>=C2=A0 =C2=A04 files changed, 185 insertions(+)
>
> 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)<= br> >=C2=A0 =C2=A0 =C2=A0 =C2=A0char *end;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0uid_t uid;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0gid_t gid;
> +=C2=A0 =C2=A0 =C2=A0int len;

I think you don't need to introduce len for --dhcp-opt as you already u= se ret for --dhcp-boot
>=C2=A0 =C2=A0 =C2=A0 =C2=A0
>=C2=A0 =C2=A0
>=C2=A0 =C2=A0 =C2=A0 =C2=A0if (c->mode =3D=3D MODE_PASTA)
> @@ -1482,7 +1483,14 @@ void conf(struct ctx *c, int argc, char **argv)=
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0die("Too many DHCP options (m= ax %d)",
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0MAX_CUSTOM_DHCP_OPTS= );
>=C2=A0 =C2=A0
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0ret =3D dhcp_opt_parse(67, optarg,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 c->custom_opts[c->custom_opts_count].val,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 sizeof(c->custom_opts[0].val));
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0if (ret < 0)
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0die("Invalid boot file value: %s&qu= ot;, optarg);
> +
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0c->custom_opts[c->custom_opts_count].code =3D 67;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0c->custom_opts[c->custom_opts_count].len =3D ret;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0if (snprintf_check(c->custom_opts[c->custom_opts_count].= str,
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 sizeof(c->custom_opts[0].str),
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 "%s", optarg))
> @@ -1503,7 +1511,15 @@ void conf(struct ctx *c, int argc, char **argv)=
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0die("Too many --dhcp-opt entr= ies (max %d)",
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0MAX_CUSTOM_DHCP_OPTS= );
>=C2=A0 =C2=A0
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0len =3D dhcp_opt_parse(optcode, comma + 1,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 c->custom_opts[c->custom_opts_count].val,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 sizeof(c->custom_opts[0].val));

you can use "ret" here too

> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0if (len < 0)
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0die("Invalid value for DHCP option = %lu: %s",
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0optcode, comma + 1);
> +
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0c->custom_opts[c->custom_opts_count].code =3D optcode; > +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0c->custom_opts[c->custom_opts_count].len =3D len;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0if (snprintf_check(c->custom_opts[c->custom_opts_count].= str,
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 sizeof(c->custom_opts[0].str),
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 "%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 @@
>=C2=A0 =C2=A0#include "log.h"
>=C2=A0 =C2=A0#include "dhcp.h"
>=C2=A0 =C2=A0
> +/**
> + * 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 {
> +=C2=A0 =C2=A0 =C2=A0[1]=C2=A0 =3D DHCP_OPT_IPV4,=C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0/* Subnet Mask */
> +=C2=A0 =C2=A0 =C2=A0[2]=C2=A0 =3D DHCP_OPT_INTEGER,=C2=A0 =C2=A0 =C2= =A0 =C2=A0 /* Time Offset */
> +=C2=A0 =C2=A0 =C2=A0[3]=C2=A0 =3D DHCP_OPT_IPV4_LIST,=C2=A0 =C2=A0 = =C2=A0 /* Router */
> +=C2=A0 =C2=A0 =C2=A0[4]=C2=A0 =3D DHCP_OPT_IPV4_LIST,=C2=A0 =C2=A0 = =C2=A0 /* Time Server */
> +=C2=A0 =C2=A0 =C2=A0[5]=C2=A0 =3D DHCP_OPT_IPV4_LIST,=C2=A0 =C2=A0 = =C2=A0 /* Name Server */
> +=C2=A0 =C2=A0 =C2=A0[6]=C2=A0 =3D DHCP_OPT_IPV4_LIST,=C2=A0 =C2=A0 = =C2=A0 /* Domain Name Server */
> +=C2=A0 =C2=A0 =C2=A0[7]=C2=A0 =3D DHCP_OPT_IPV4_LIST,=C2=A0 =C2=A0 = =C2=A0 /* Log Server */
> +=C2=A0 =C2=A0 =C2=A0[8]=C2=A0 =3D DHCP_OPT_IPV4_LIST,=C2=A0 =C2=A0 = =C2=A0 /* Cookie Server */
> +=C2=A0 =C2=A0 =C2=A0[9]=C2=A0 =3D DHCP_OPT_IPV4_LIST,=C2=A0 =C2=A0 = =C2=A0 /* LPR Server */
> +=C2=A0 =C2=A0 =C2=A0[10] =3D DHCP_OPT_IPV4_LIST,=C2=A0 =C2=A0 =C2=A0 = /* Impress Server */
> +=C2=A0 =C2=A0 =C2=A0[11] =3D DHCP_OPT_IPV4_LIST,=C2=A0 =C2=A0 =C2=A0 = /* Resource Location Server */
> +=C2=A0 =C2=A0 =C2=A0[12] =3D DHCP_OPT_STR,=C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 /* Host Name */
> +=C2=A0 =C2=A0 =C2=A0[13] =3D DHCP_OPT_INTEGER,=C2=A0 =C2=A0 =C2=A0 = =C2=A0 /* Boot File Size */
> +=C2=A0 =C2=A0 =C2=A0[15] =3D DHCP_OPT_STR,=C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 /* Domain Name */
> +=C2=A0 =C2=A0 =C2=A0[16] =3D DHCP_OPT_IPV4,=C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0/* Swap Server */
> +=C2=A0 =C2=A0 =C2=A0[17] =3D DHCP_OPT_STR,=C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 /* Root Path */
> +=C2=A0 =C2=A0 =C2=A0[19] =3D DHCP_OPT_INTEGER,=C2=A0 =C2=A0 =C2=A0 = =C2=A0 /* IP Forwarding */
> +=C2=A0 =C2=A0 =C2=A0[23] =3D DHCP_OPT_INTEGER,=C2=A0 =C2=A0 =C2=A0 = =C2=A0 /* Default IP TTL */
> +=C2=A0 =C2=A0 =C2=A0[26] =3D DHCP_OPT_INTEGER,=C2=A0 =C2=A0 =C2=A0 = =C2=A0 /* Interface MTU */
> +=C2=A0 =C2=A0 =C2=A0[28] =3D DHCP_OPT_IPV4,=C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0/* Broadcast Address */
> +=C2=A0 =C2=A0 =C2=A0[33] =3D DHCP_OPT_IPV4_LIST,=C2=A0 =C2=A0 =C2=A0 = /* Static Routes */
> +=C2=A0 =C2=A0 =C2=A0[37] =3D DHCP_OPT_INTEGER,=C2=A0 =C2=A0 =C2=A0 = =C2=A0 /* TCP Default TTL */
> +=C2=A0 =C2=A0 =C2=A0[38] =3D DHCP_OPT_INTEGER,=C2=A0 =C2=A0 =C2=A0 = =C2=A0 /* TCP Keepalive Interval */
> +=C2=A0 =C2=A0 =C2=A0[40] =3D DHCP_OPT_STR,=C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 /* NIS Domain Name */
> +=C2=A0 =C2=A0 =C2=A0[41] =3D DHCP_OPT_IPV4_LIST,=C2=A0 =C2=A0 =C2=A0 = /* NIS Servers */
> +=C2=A0 =C2=A0 =C2=A0[42] =3D DHCP_OPT_IPV4_LIST,=C2=A0 =C2=A0 =C2=A0 = /* NTP Servers */
> +=C2=A0 =C2=A0 =C2=A0[44] =3D DHCP_OPT_IPV4_LIST,=C2=A0 =C2=A0 =C2=A0 = /* NetBIOS Name Server */
> +=C2=A0 =C2=A0 =C2=A0[50] =3D DHCP_OPT_IPV4,=C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0/* Requested IP Address */
> +=C2=A0 =C2=A0 =C2=A0[51] =3D DHCP_OPT_INTEGER,=C2=A0 =C2=A0 =C2=A0 = =C2=A0 /* IP Address Lease Time */
> +=C2=A0 =C2=A0 =C2=A0[53] =3D DHCP_OPT_INTEGER,=C2=A0 =C2=A0 =C2=A0 = =C2=A0 /* DHCP Message Type */
> +=C2=A0 =C2=A0 =C2=A0[54] =3D DHCP_OPT_IPV4,=C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0/* Server Identifier */
> +=C2=A0 =C2=A0 =C2=A0[55] =3D DHCP_OPT_STR,=C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 /* Parameter Request List */

This is a client option, I don't think we need to manage it.

> +=C2=A0 =C2=A0 =C2=A0[57] =3D DHCP_OPT_INTEGER,=C2=A0 =C2=A0 =C2=A0 = =C2=A0 /* Max DHCP Message Size */
> +=C2=A0 =C2=A0 =C2=A0[58] =3D DHCP_OPT_INTEGER,=C2=A0 =C2=A0 =C2=A0 = =C2=A0 /* Renewal (T1) Time */
> +=C2=A0 =C2=A0 =C2=A0[59] =3D DHCP_OPT_INTEGER,=C2=A0 =C2=A0 =C2=A0 = =C2=A0 /* Rebinding (T2) Time */
> +=C2=A0 =C2=A0 =C2=A0[60] =3D DHCP_OPT_STR,=C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 /* Vendor Class Identifier */
> +=C2=A0 =C2=A0 =C2=A0[61] =3D DHCP_OPT_STR,=C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 /* Client Identifier */

This is also a client option.

> +=C2=A0 =C2=A0 =C2=A0[66] =3D DHCP_OPT_STR,=C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 /* TFTP Server Name */
> +=C2=A0 =C2=A0 =C2=A0[67] =3D DHCP_OPT_STR,=C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 /* Bootfile Name */
> +=C2=A0 =C2=A0 =C2=A0[119] =3D DHCP_OPT_STR,=C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0/* Domain Search List */

This is not really a string as this uses the message compression described = in RFC 1035,
4.1.4. (See also 3. Example in rfc3397). I'm not sure we can encode thi= s manually on the
command line. And RFC 3396 defines how to encode search string for more tha= n 255
characters length

> +=C2=A0 =C2=A0 =C2=A0[252] =3D DHCP_OPT_STR,=C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0/* WPAD URL */
> +};
> +
> +/**
> + * dhcp_opt_int_width - Integer width in bytes for INTEGER-typed opti= ons
> + */
> +static const uint8_t dhcp_opt_int_width[256] =3D {
> +=C2=A0 =C2=A0 =C2=A0[2]=C2=A0 =3D 4,=C2=A0 =C2=A0 =C2=A0 =C2=A0/* Tim= e Offset */
> +=C2=A0 =C2=A0 =C2=A0[13] =3D 2,=C2=A0 =C2=A0 =C2=A0 =C2=A0/* Boot Fil= e Size */
> +=C2=A0 =C2=A0 =C2=A0[19] =3D 1,=C2=A0 =C2=A0 =C2=A0 =C2=A0/* IP Forwa= rding */
> +=C2=A0 =C2=A0 =C2=A0[23] =3D 1,=C2=A0 =C2=A0 =C2=A0 =C2=A0/* Default = IP TTL */
> +=C2=A0 =C2=A0 =C2=A0[26] =3D 2,=C2=A0 =C2=A0 =C2=A0 =C2=A0/* Interfac= e MTU */
> +=C2=A0 =C2=A0 =C2=A0[37] =3D 1,=C2=A0 =C2=A0 =C2=A0 =C2=A0/* TCP Defa= ult TTL */
> +=C2=A0 =C2=A0 =C2=A0[38] =3D 4,=C2=A0 =C2=A0 =C2=A0 =C2=A0/* TCP Keep= alive Interval */
> +=C2=A0 =C2=A0 =C2=A0[51] =3D 4,=C2=A0 =C2=A0 =C2=A0 =C2=A0/* IP Addre= ss Lease Time */
> +=C2=A0 =C2=A0 =C2=A0[53] =3D 1,=C2=A0 =C2=A0 =C2=A0 =C2=A0/* DHCP Mes= sage Type */
> +=C2=A0 =C2=A0 =C2=A0[57] =3D 2,=C2=A0 =C2=A0 =C2=A0 =C2=A0/* Max DHCP= Message Size */
> +=C2=A0 =C2=A0 =C2=A0[58] =3D 4,=C2=A0 =C2=A0 =C2=A0 =C2=A0/* Renewal = (T1) Time */
> +=C2=A0 =C2=A0 =C2=A0[59] =3D 4,=C2=A0 =C2=A0 =C2=A0 =C2=A0/* Rebindin= g (T2) Time */
> +};
> +
> +#define DHCP_OPT_PARSE_BUF=C2=A0 =C2=A01024

Do we need 1024 bytes, all options are bounded to 256 bytes.
> +
> +/**
> + * dhcp_opt_parse() - Parse a DHCP option value
> + * @code:=C2=A0 =C2=A0 DHCP option code
> + * @str:=C2=A0 =C2=A0 =C2=A0DHCP Value string from command line
> + * @buf:=C2=A0 =C2=A0 =C2=A0Output buffer
> + * @buf_len: Size 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 buf_len)
> +{
> +=C2=A0 =C2=A0 =C2=A0enum dhcp_opt_type type =3D dhcp_opt_types[code];=
> +=C2=A0 =C2=A0 =C2=A0char tmp[DHCP_OPT_PARSE_BUF];
> +=C2=A0 =C2=A0 =C2=A0char *tok, *saveptr, *end;
> +=C2=A0 =C2=A0 =C2=A0struct in_addr addr;
> +=C2=A0 =C2=A0 =C2=A0unsigned long val;
> +=C2=A0 =C2=A0 =C2=A0unsigned int i;
> +=C2=A0 =C2=A0 =C2=A0uint8_t width;
> +=C2=A0 =C2=A0 =C2=A0size_t slen;
> +=C2=A0 =C2=A0 =C2=A0int len;
> +
> +=C2=A0 =C2=A0 =C2=A0switch (type) {
> +=C2=A0 =C2=A0 =C2=A0case DHCP_OPT_NONE:
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0die("Unsupported= DHCP option: %u,"
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0" = see passt(1) for supported codes", code);
> +=C2=A0 =C2=A0 =C2=A0case DHCP_OPT_IPV4:
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (inet_pton(AF_INET= , str, &addr) !=3D 1)
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0return -1;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (buf_len < size= of(addr))
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0return -1;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0memcpy(buf, &addr= , sizeof(addr));
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return sizeof(addr);<= br> > +=C2=A0 =C2=A0 =C2=A0case DHCP_OPT_IPV4_LIST:
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0len =3D 0;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (snprintf_check(tm= p, sizeof(tmp), "%s", str))
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0return -1;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0for (tok =3D strtok_r= (tmp, ",", &saveptr); tok;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 tok = =3D strtok_r(NULL, ",", &saveptr)) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0if (inet_pton(AF_INET, tok, &addr) !=3D 1)
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return -1;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0if (len + (int)sizeof(addr) > (int)buf_len)
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return -1;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0memcpy(buf + len, &addr, sizeof(addr));
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0len +=3D sizeof(addr);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0}
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return len;
> +=C2=A0 =C2=A0 =C2=A0case DHCP_OPT_INTEGER:
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0width =3D dhcp_opt_in= t_width[code];
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0val =3D strtoul(str, = &end, 0);
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (*end || buf_len &= lt; width)
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0return -1;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (width < 4 &= ;& val >=3D (1UL << (width * 8)))
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0return -1;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0for (i =3D 0; i < = width; i++)
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0buf[i] =3D (val >> ((width - 1 - i) * 8)) & 0xff;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return width;
> +=C2=A0 =C2=A0 =C2=A0case DHCP_OPT_STR:
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0slen =3D strlen(str);=
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (!slen || slen >= ;=3D buf_len)
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0return -1;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0strncpy((char *)buf, = str, buf_len);
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return slen;
> +=C2=A0 =C2=A0 =C2=A0}
> +
> +=C2=A0 =C2=A0 =C2=A0return -1;
> +}
> +
>=C2=A0 =C2=A0/**
>=C2=A0 =C2=A0 * struct opt - DHCP option
>=C2=A0 =C2=A0 * @sent:=C2=A0 =C2=A0Convenience 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 @@
>=C2=A0 =C2=A0#ifndef DHCP_H
>=C2=A0 =C2=A0#define DHCP_H
>=C2=A0 =C2=A0
> +/**
> + * enum dhcp_opt_type - DHCP option value types per RFC 2132
> + * @DHCP_OPT_NONE:=C2=A0 =C2=A0Unsupported or unknown option
> + * @DHCP_OPT_STR:=C2=A0 =C2=A0 Variable-length string
> + * @DHCP_OPT_IPV4:=C2=A0 =C2=A0Single IPv4 address
> + * @DHCP_OPT_IPV4_LIST:Multiple IPv4 addresses, comma-separated
> + * @DHCP_OPT_INTEGER:=C2=A0 =C2=A0 =C2=A0 =C2=A0 Unsigned integer (1,= 2, or 4 bytes)
> + */
> +enum dhcp_opt_type {
> +=C2=A0 =C2=A0 =C2=A0DHCP_OPT_NONE,
> +=C2=A0 =C2=A0 =C2=A0DHCP_OPT_STR,
> +=C2=A0 =C2=A0 =C2=A0DHCP_OPT_IPV4,
> +=C2=A0 =C2=A0 =C2=A0DHCP_OPT_IPV4_LIST,
> +=C2=A0 =C2=A0 =C2=A0DHCP_OPT_INTEGER,
> +};
> +
>=C2=A0 =C2=A0int dhcp(const struct ctx *c, struct iov_tail *data);
>=C2=A0 =C2=A0void dhcp_init(void);
> +int dhcp_opt_parse(uint8_t code, const char *str, uint8_t *buf, size_= t buf_len);
>=C2=A0 =C2=A0
>=C2=A0 =C2=A0#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 {
>=C2=A0 =C2=A0 * @fqdn:=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0Guest FQ= DN
>=C2=A0 =C2=A0 * @custom_opts:=C2=A0 =C2=A0 User-specified DHCP options = from --dhcp-opt
>=C2=A0 =C2=A0 * @custom_opts.code:=C2=A0 =C2=A0 =C2=A0 =C2=A0DHCP optio= n code
> + * @custom_opts.len: Length of binary value in @val
> + * @custom_opts.val: Binary-encoded option value
>=C2=A0 =C2=A0 * @custom_opts.str:=C2=A0 =C2=A0 =C2=A0 =C2=A0 Original s= tring value from command line
>=C2=A0 =C2=A0 * @custom_opts_count:=C2=A0 =C2=A0 =C2=A0 Number of entri= es in @custom_opts
>=C2=A0 =C2=A0 * @ifi6:=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0Template= interface for IPv6, -1: none, 0: IPv6 disabled
> @@ -271,6 +273,8 @@ struct ctx {
>=C2=A0 =C2=A0
>=C2=A0 =C2=A0 =C2=A0 =C2=A0struct {
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint8_t code; > +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint8_t len;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint8_t val[255];
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0char str[256];
Why do we need to keep str[] once the value is encoded into val[]?

To print the option value as entered by user.

anskuma@anskuma-thinkpadp1gen7:~/Documents/passt$ ./passt -f =C2= =A0 --dhcp-opt 60,HTTPClient --dhcp-opt 67,http://192.168.1.1:8080/alpine.iso --dhcp-opt 12,testhos= t =C2=A0 --dhcp-opt 15,test.example.com= =C2=A0 --dhcp-opt 6,8.8.8.8,8.8.4.4 =C2=A0 --dhcp-opt 26,1400 =C2=A0 -= -dhcp-opt 42,192.168.1.1 =C2=A0 --dhcp-opt 51,360 --dhcp-opt 6,1.1.1.1,9.9.= 9.9
UNIX domain socket bound at /tmp/passt_1.socket
No IPv6 nameserve= r available for NDP/DHCPv6
Template interface: wlp9s0f0 (IPv4), wlp9s0f0= (IPv6)
MAC:
=C2=A0 =C2=A0 host: 9a:55:9a:55:9a:55
=C2=A0 =C2=A0 N= AT to host 127.0.0.1: 192.168.1.1
DHCP:=
=C2=A0 =C2=A0 assign: 192.168.1.9
=C2=A0 =C2=A0 mask: 255.255.255.0<= br>=C2=A0 =C2=A0 router: 192.168.1.1
=C2=A0 =C2=A0 option 60: HTTPCli= ent
=C2=A0 =C2=A0 option 67: http://192.168.1.1:8080/alpine.iso
=C2=A0 =C2=A0 option 12: test= host
=C2=A0 =C2=A0 option 15: test.e= xample.com
=C2=A0 =C2=A0 option 6: 1.1.1.1,9.9.9.9
=C2=A0 =C2=A0 = option 26: 1400
=C2=A0 =C2=A0 option 42: 192.168.1.1
=C2=A0 =C2=A0 op= tion 51: 360

=C2=A0

>=C2=A0 =C2=A0 =C2=A0 =C2=A0} custom_opts[MAX_CUSTOM_DHCP_OPTS];
>=C2=A0 =C2=A0 =C2=A0 =C2=A0int custom_opts_count;

Thanks,
Laurent

--00000000000041b8fc0652da26d8--