From: Alan T. DeKok Date: Sun, 9 Jul 2023 13:55:49 +0000 (-0400) Subject: concatenate DHCPv4 options X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f5b39291adf7107ff6de4c073670b79aaed0197d;p=thirdparty%2Ffreeradius-server.git concatenate DHCPv4 options so that we don't encode a new header for TLV children when the TLV option still has room to encode data. --- diff --git a/src/protocols/dhcpv4/encode.c b/src/protocols/dhcpv4/encode.c index f9a6444c358..e8138f218e2 100644 --- a/src/protocols/dhcpv4/encode.c +++ b/src/protocols/dhcpv4/encode.c @@ -491,22 +491,25 @@ static ssize_t encode_tlv(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *cursor, void *encode_ctx) { - ssize_t len; + ssize_t len, option_len; fr_dbuff_t work_dbuff = FR_DBUFF(dbuff); - fr_dbuff_marker_t hdr, next_hdr, dest, hdr_io; + fr_dbuff_marker_t hdr, dst, tmp; fr_pair_t const *vp = fr_dcursor_current(cursor); fr_dict_attr_t const *da = da_stack->da[depth]; - uint8_t option_number, option_len; + uint8_t option_number; FR_PROTO_STACK_PRINT(da_stack, depth); + /* + * Where the TLV header starts. + */ fr_dbuff_marker(&hdr, &work_dbuff); + /* * These are set before use; their initial value doesn't matter. */ - fr_dbuff_marker(&next_hdr, &work_dbuff); - fr_dbuff_marker(&dest, &work_dbuff); - fr_dbuff_marker(&hdr_io, &work_dbuff); + fr_dbuff_marker(&dst, &work_dbuff); + fr_dbuff_marker(&tmp, &work_dbuff); /* * Write out the option number and length (which, unlike RADIUS, @@ -524,48 +527,54 @@ static ssize_t encode_tlv(fr_dbuff_t *dbuff, if (len < 0) return len; if (len == 0) break; /* Insufficient space */ + option_len += len; + /* * If the newly added data fits within the current option, then * update the header, and go to the next option. */ - if (option_len + len <= 255) { - option_len += len; - fr_dbuff_set(&hdr_io, fr_dbuff_current(&hdr) + 1); - fr_dbuff_in_bytes(&hdr_io, option_len); + if (option_len <= 255) { + fr_dbuff_set(&tmp, fr_dbuff_current(&hdr) + 1); + fr_dbuff_in_bytes(&tmp, (uint8_t) option_len); + } else { + next_hdr: + option_len -= 255; + /* - * If there was data before the new data, create a new header - * and advance to it. + * Ensure that we have room for another TLV header. */ - if (option_len > 0) { - if (fr_dbuff_extend_lowat(NULL, &work_dbuff, 2) < 2) break; - fr_dbuff_advance(&work_dbuff, 2); + if (fr_dbuff_extend_lowat(NULL, &work_dbuff, 2) < 2) break; + fr_dbuff_advance(&work_dbuff, 2); - fr_dbuff_set(&next_hdr, fr_dbuff_current(&hdr) + (option_len + 2)); - fr_dbuff_set(&hdr, &next_hdr); + /* + * The first TLV is length 255 + */ + fr_dbuff_set(&tmp, fr_dbuff_current(&hdr) + 1); + fr_dbuff_in_bytes(&tmp, 255); - fr_dbuff_set(&dest, fr_dbuff_current(&next_hdr) + 2); - fr_dbuff_move(&dest, &next_hdr, len); + /* + * Point to where the next header should be + */ + fr_dbuff_set(&tmp, fr_dbuff_current(&hdr) + 255 + 2); + fr_dbuff_set(&hdr, &tmp); - option_len = 0; - fr_dbuff_set(&hdr_io, &hdr); - fr_dbuff_in_bytes(&hdr_io, option_number, option_len); - } + /* + * Move the encoded data 2 bytes forward + * to account for the new header. + */ + fr_dbuff_set(&dst, fr_dbuff_current(&tmp) + 2); + fr_dbuff_move(&dst, &tmp, option_len); /* - * If the new data fits entirely within the (possibly new, - * but definitely unused) option, just use it. Otherwise, - * it must be split across multiple options. + * Update the header length */ - if (len <= 255) { - option_len += len; - fr_dbuff_set(&hdr_io, fr_dbuff_current(&hdr) + 1); - fr_dbuff_in_bytes(&hdr_io, option_len); + fr_dbuff_set(&tmp, &hdr); + if (option_len < 255) { + fr_dbuff_in_bytes(&tmp, option_number, (uint8_t) option_len); } else { - if (!extend_option(&work_dbuff, &hdr, len)) break; - fr_dbuff_set(&hdr_io, fr_dbuff_current(&hdr) + 1); - len = fr_dbuff_out(&option_len, &hdr_io); - if (len < 0) return len; + fr_dbuff_in_bytes(&tmp, option_number, 0); + goto next_hdr; } } diff --git a/src/tests/unit/protocols/dhcpv4/base.txt b/src/tests/unit/protocols/dhcpv4/base.txt index efb4cff5752..34e5c951293 100644 --- a/src/tests/unit/protocols/dhcpv4/base.txt +++ b/src/tests/unit/protocols/dhcpv4/base.txt @@ -20,7 +20,6 @@ match Relay-Agent-Information.Circuit-Id = 0xabcdef, Relay-Agent-Information.Rem encode-pair Relay-Agent-Information = { Circuit-Id = 0xabcdef, Remote-Id = 0x010203040506 } match 52 0d 01 03 ab cd ef 02 06 01 02 03 04 05 06 - encode-pair Subnet-Mask = 255.255.0.0 match 01 04 ff ff 00 00 @@ -49,7 +48,16 @@ match Message-Type = Discover, Client-Identifier = 0x01001ceaadac1e, Parameter-R # Two sub-options 82, that cannot fit in a single option. # encode-pair Relay-Agent-Information.Circuit-Id = 'oh hai this is an agent, how are you doing DHCP server? this is a really long agent circuit id, which will occupy most of the maximum size for an option so that the next sub option will not fit and a new option will be needed', Relay-Agent-Information.Remote-Id = 'trying to add a sub option agent remote id' -match 52 e3 01 e1 6f 68 20 68 61 69 20 74 68 69 73 20 69 73 20 61 6e 20 61 67 65 6e 74 2c 20 68 6f 77 20 61 72 65 20 79 6f 75 20 64 6f 69 6e 67 20 44 48 43 50 20 73 65 72 76 65 72 3f 20 74 68 69 73 20 69 73 20 61 20 72 65 61 6c 6c 79 20 6c 6f 6e 67 20 61 67 65 6e 74 20 63 69 72 63 75 69 74 20 69 64 2c 20 77 68 69 63 68 20 77 69 6c 6c 20 6f 63 63 75 70 79 20 6d 6f 73 74 20 6f 66 20 74 68 65 20 6d 61 78 69 6d 75 6d 20 73 69 7a 65 20 66 6f 72 20 61 6e 20 6f 70 74 69 6f 6e 20 73 6f 20 74 68 61 74 20 74 68 65 20 6e 65 78 74 20 73 75 62 20 6f 70 74 69 6f 6e 20 77 69 6c 6c 20 6e 6f 74 20 66 69 74 20 61 6e 64 20 61 20 6e 65 77 20 6f 70 74 69 6f 6e 20 77 69 6c 6c 20 62 65 20 6e 65 65 64 65 64 52 2c 02 2a 74 72 79 69 6e 67 20 74 6f 20 61 64 64 20 61 20 73 75 62 20 6f 70 74 69 6f 6e 20 61 67 65 6e 74 20 72 65 6d 6f 74 65 20 69 64 + +#match 52 e3 01 e1 6f 68 20 68 61 69 20 74 68 69 73 20 69 73 20 61 6e 20 61 67 65 6e 74 2c 20 68 6f 77 20 61 72 65 20 79 6f 75 20 64 6f 69 6e 67 20 44 48 43 50 20 73 65 72 76 65 72 3f 20 74 68 69 73 20 69 73 20 61 20 72 65 61 6c 6c 79 20 6c 6f 6e 67 20 61 67 65 6e 74 20 63 69 72 63 75 69 74 20 69 64 2c 20 77 68 69 63 68 20 77 69 6c 6c 20 6f 63 63 75 70 79 20 6d 6f 73 74 20 6f 66 20 74 68 65 20 6d 61 78 69 6d 75 6d 20 73 69 7a 65 20 66 6f 72 20 61 6e 20 6f 70 74 69 6f 6e 20 73 6f 20 74 68 61 74 20 74 68 65 20 6e 65 78 74 20 73 75 62 20 6f 70 74 69 6f 6e 20 77 69 6c 6c 20 6e 6f 74 20 66 69 74 20 61 6e 64 20 61 20 6e 65 77 20 6f 70 74 69 6f 6e 20 77 69 6c 6c 20 62 65 20 6e 65 65 64 65 64 52 2c 02 2a 74 72 79 69 6e 67 20 74 6f 20 61 64 64 20 61 20 73 75 62 20 6f 70 74 69 6f 6e 20 61 67 65 6e 74 20 72 65 6d 6f 74 65 20 69 64 + +match 52 ff 01 e1 6f 68 20 68 61 69 20 74 68 69 73 20 69 73 20 61 6e 20 61 67 65 6e 74 2c 20 68 6f 77 20 61 72 65 20 79 6f 75 20 64 6f 69 6e 67 20 44 48 43 50 20 73 65 72 76 65 72 3f 20 74 68 69 73 20 69 73 20 61 20 72 65 61 6c 6c 79 20 6c 6f 6e 67 20 61 67 65 6e 74 20 63 69 72 63 75 69 74 20 69 64 2c 20 77 68 69 63 68 20 77 69 6c 6c 20 6f 63 63 75 70 79 20 6d 6f 73 74 20 6f 66 20 74 68 65 20 6d 61 78 69 6d 75 6d 20 73 69 7a 65 20 66 6f 72 20 61 6e 20 6f 70 74 69 6f 6e 20 73 6f 20 74 68 61 74 20 74 68 65 20 6e 65 78 74 20 73 75 62 20 6f 70 74 69 6f 6e 20 77 69 6c 6c 20 6e 6f 74 20 66 69 74 20 61 6e 64 20 61 20 6e 65 77 20 6f 70 74 69 6f 6e 20 77 69 6c 6c 20 62 65 20 6e 65 65 64 65 64 02 2a 74 72 79 69 6e 67 20 74 6f 20 61 64 64 20 61 20 73 75 62 20 6f 70 74 69 6f 6e 52 10 20 61 67 65 6e 74 20 72 65 6d 6f 74 65 20 69 64 + +# +# The fields are "octets", and therefore decode as hex. +# +decode-pair - +match Relay-Agent-Information.Circuit-Id = 0x6f6820686169207468697320697320616e206167656e742c20686f772061726520796f7520646f696e672044484350207365727665723f20746869732069732061207265616c6c79206c6f6e67206167656e7420636972637569742069642c2077686963682077696c6c206f6363757079206d6f7374206f6620746865206d6178696d756d2073697a6520666f7220616e206f7074696f6e20736f207468617420746865206e65787420737562206f7074696f6e2077696c6c206e6f742066697420616e642061206e6577206f7074696f6e2077696c6c206265206e6565646564, Relay-Agent-Information.Remote-Id = 0x747279696e6720746f20616464206120737562206f7074696f6e206167656e742072656d6f7465206964 # An empty octets option encode-pair Merit-Dump-File = '' @@ -105,4 +113,4 @@ decode-pair - match Relay-Agent-Information.Circuit-Id = 0x3132333435363738396131323334353637383962313233343536373839633132333435363738396431323334353637383965313233343536373839663132333435363738396731323334353637383968313233343536373839613132333435363738396131323334353637383961313233343536373839613132333435363738396131323334353637383961313233343536373839613132333435363738396131323334353637383961313233343536373839613132333435363738396131323334353637383961313233343536373839613132333435363738396131323334353637383961313233343536373839613132333435363738396178797a count -match 45 +match 47