isisd: fix #10505 using base64 encoding

Using base64 instead of the raw string to encode
the binary data.

Signed-off-by: whichbug <whichbug@github.com>
This commit is contained in:
whichbug 2022-02-10 22:49:41 -05:00
parent 6142a17949
commit ac3133450d
6 changed files with 314 additions and 8 deletions

View File

@ -245,7 +245,7 @@ void isis_notif_max_area_addr_mismatch(const struct isis_circuit *circuit,
data = yang_data_new_uint8(xpath_arg, max_area_addrs);
listnode_add(arguments, data);
snprintf(xpath_arg, sizeof(xpath_arg), "%s/raw-pdu", xpath);
data = yang_data_new(xpath_arg, raw_pdu);
data = yang_data_new_binary(xpath_arg, raw_pdu, raw_pdu_len);
listnode_add(arguments, data);
hook_call(isis_hook_max_area_addr_mismatch, circuit, max_area_addrs,
@ -270,7 +270,7 @@ void isis_notif_authentication_type_failure(const struct isis_circuit *circuit,
notif_prep_instance_hdr(xpath, area, "default", arguments);
notif_prepr_iface_hdr(xpath, circuit, arguments);
snprintf(xpath_arg, sizeof(xpath_arg), "%s/raw-pdu", xpath);
data = yang_data_new(xpath_arg, raw_pdu);
data = yang_data_new_binary(xpath_arg, raw_pdu, raw_pdu_len);
listnode_add(arguments, data);
hook_call(isis_hook_authentication_type_failure, circuit, raw_pdu,
@ -294,7 +294,7 @@ void isis_notif_authentication_failure(const struct isis_circuit *circuit,
notif_prep_instance_hdr(xpath, area, "default", arguments);
notif_prepr_iface_hdr(xpath, circuit, arguments);
snprintf(xpath_arg, sizeof(xpath_arg), "%s/raw-pdu", xpath);
data = yang_data_new(xpath_arg, raw_pdu);
data = yang_data_new_binary(xpath_arg, raw_pdu, raw_pdu_len);
listnode_add(arguments, data);
hook_call(isis_hook_authentication_failure, circuit, raw_pdu,
@ -361,7 +361,7 @@ void isis_notif_reject_adjacency(const struct isis_circuit *circuit,
data = yang_data_new_string(xpath_arg, reason);
listnode_add(arguments, data);
snprintf(xpath_arg, sizeof(xpath_arg), "%s/raw-pdu", xpath);
data = yang_data_new(xpath_arg, raw_pdu);
data = yang_data_new_binary(xpath_arg, raw_pdu, raw_pdu_len);
listnode_add(arguments, data);
hook_call(isis_hook_reject_adjacency, circuit, raw_pdu, raw_pdu_len);
@ -384,7 +384,7 @@ void isis_notif_area_mismatch(const struct isis_circuit *circuit,
notif_prep_instance_hdr(xpath, area, "default", arguments);
notif_prepr_iface_hdr(xpath, circuit, arguments);
snprintf(xpath_arg, sizeof(xpath_arg), "%s/raw-pdu", xpath);
data = yang_data_new(xpath_arg, raw_pdu);
data = yang_data_new_binary(xpath_arg, raw_pdu, raw_pdu_len);
listnode_add(arguments, data);
hook_call(isis_hook_area_mismatch, circuit, raw_pdu, raw_pdu_len);
@ -467,7 +467,7 @@ void isis_notif_id_len_mismatch(const struct isis_circuit *circuit,
data = yang_data_new_uint8(xpath_arg, rcv_id_len);
listnode_add(arguments, data);
snprintf(xpath_arg, sizeof(xpath_arg), "%s/raw-pdu", xpath);
data = yang_data_new(xpath_arg, raw_pdu);
data = yang_data_new_binary(xpath_arg, raw_pdu, raw_pdu_len);
listnode_add(arguments, data);
hook_call(isis_hook_id_len_mismatch, circuit, rcv_id_len, raw_pdu,
@ -495,7 +495,7 @@ void isis_notif_version_skew(const struct isis_circuit *circuit,
data = yang_data_new_uint8(xpath_arg, version);
listnode_add(arguments, data);
snprintf(xpath_arg, sizeof(xpath_arg), "%s/raw-pdu", xpath);
data = yang_data_new(xpath_arg, raw_pdu);
data = yang_data_new_binary(xpath_arg, raw_pdu, raw_pdu_len);
listnode_add(arguments, data);
hook_call(isis_hook_version_skew, circuit, version, raw_pdu,
@ -525,7 +525,7 @@ void isis_notif_lsp_error(const struct isis_circuit *circuit,
data = yang_data_new_string(xpath_arg, rawlspid_print(lsp_id));
listnode_add(arguments, data);
snprintf(xpath_arg, sizeof(xpath_arg), "%s/raw-pdu", xpath);
data = yang_data_new(xpath_arg, raw_pdu);
data = yang_data_new_binary(xpath_arg, raw_pdu, raw_pdu_len);
listnode_add(arguments, data);
/* ignore offset and tlv_type which cannot be set properly */

193
lib/base64.c Normal file
View File

@ -0,0 +1,193 @@
/*
* This is part of the libb64 project, and has been placed in the public domain.
* For details, see http://sourceforge.net/projects/libb64
*/
#include "base64.h"
static const int CHARS_PER_LINE = 72;
static const char *ENCODING =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
void base64_init_encodestate(struct base64_encodestate *state_in)
{
state_in->step = step_A;
state_in->result = 0;
state_in->stepcount = 0;
}
char base64_encode_value(char value_in)
{
if (value_in > 63)
return '=';
return ENCODING[(int)value_in];
}
int base64_encode_block(const char *plaintext_in, int length_in, char *code_out,
struct base64_encodestate *state_in)
{
const char *plainchar = plaintext_in;
const char *const plaintextend = plaintext_in + length_in;
char *codechar = code_out;
char result;
char fragment;
result = state_in->result;
switch (state_in->step) {
while (1) {
case step_A:
if (plainchar == plaintextend) {
state_in->result = result;
state_in->step = step_A;
return codechar - code_out;
}
fragment = *plainchar++;
result = (fragment & 0x0fc) >> 2;
*codechar++ = base64_encode_value(result);
result = (fragment & 0x003) << 4;
/* fall through */
case step_B:
if (plainchar == plaintextend) {
state_in->result = result;
state_in->step = step_B;
return codechar - code_out;
}
fragment = *plainchar++;
result |= (fragment & 0x0f0) >> 4;
*codechar++ = base64_encode_value(result);
result = (fragment & 0x00f) << 2;
/* fall through */
case step_C:
if (plainchar == plaintextend) {
state_in->result = result;
state_in->step = step_C;
return codechar - code_out;
}
fragment = *plainchar++;
result |= (fragment & 0x0c0) >> 6;
*codechar++ = base64_encode_value(result);
result = (fragment & 0x03f) >> 0;
*codechar++ = base64_encode_value(result);
++(state_in->stepcount);
if (state_in->stepcount == CHARS_PER_LINE/4) {
*codechar++ = '\n';
state_in->stepcount = 0;
}
}
}
/* control should not reach here */
return codechar - code_out;
}
int base64_encode_blockend(char *code_out, struct base64_encodestate *state_in)
{
char *codechar = code_out;
switch (state_in->step) {
case step_B:
*codechar++ = base64_encode_value(state_in->result);
*codechar++ = '=';
*codechar++ = '=';
break;
case step_C:
*codechar++ = base64_encode_value(state_in->result);
*codechar++ = '=';
break;
case step_A:
break;
}
*codechar++ = '\n';
return codechar - code_out;
}
signed char base64_decode_value(signed char value_in)
{
static const signed char decoding[] = {
62, -1, -1, -1, 63, 52, 53, 54,
55, 56, 57, 58, 59, 60, 61, -1,
-1, -1, -2, -1, -1, -1, 0, 1,
2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17,
18, 19, 20, 21, 22, 23, 24, 25,
-1, -1, -1, -1, -1, -1, 26, 27,
28, 29, 30, 31, 32, 33, 34, 35,
36, 37, 38, 39, 40, 41, 42, 43,
44, 45, 46, 47, 48, 49, 50, 51
};
value_in -= 43;
if (value_in < 0 || value_in >= 80)
return -1;
return decoding[(int)value_in];
}
void base64_init_decodestate(struct base64_decodestate *state_in)
{
state_in->step = step_a;
state_in->plainchar = 0;
}
int base64_decode_block(const char *code_in, int length_in, char *plaintext_out,
struct base64_decodestate *state_in)
{
const char *codec = code_in;
char *plainc = plaintext_out;
signed char fragmt;
*plainc = state_in->plainchar;
switch (state_in->step) {
while (1) {
case step_a:
do {
if (codec == code_in+length_in) {
state_in->step = step_a;
state_in->plainchar = *plainc;
return plainc - plaintext_out;
}
fragmt = base64_decode_value(*codec++);
} while (fragmt < 0);
*plainc = (fragmt & 0x03f) << 2;
/* fall through */
case step_b:
do {
if (codec == code_in+length_in) {
state_in->step = step_b;
state_in->plainchar = *plainc;
return plainc - plaintext_out;
}
fragmt = base64_decode_value(*codec++);
} while (fragmt < 0);
*plainc++ |= (fragmt & 0x030) >> 4;
*plainc = (fragmt & 0x00f) << 4;
/* fall through */
case step_c:
do {
if (codec == code_in+length_in) {
state_in->step = step_c;
state_in->plainchar = *plainc;
return plainc - plaintext_out;
}
fragmt = base64_decode_value(*codec++);
} while (fragmt < 0);
*plainc++ |= (fragmt & 0x03c) >> 2;
*plainc = (fragmt & 0x003) << 6;
/* fall through */
case step_d:
do {
if (codec == code_in+length_in) {
state_in->step = step_d;
state_in->plainchar = *plainc;
return plainc - plaintext_out;
}
fragmt = base64_decode_value(*codec++);
} while (fragmt < 0);
*plainc++ |= (fragmt & 0x03f);
}
}
/* control should not reach here */
return plainc - plaintext_out;
}

45
lib/base64.h Normal file
View File

@ -0,0 +1,45 @@
/*
* This is part of the libb64 project, and has been placed in the public domain.
* For details, see http://sourceforge.net/projects/libb64
*/
#ifndef _BASE64_H_
#define _BASE64_H_
enum base64_encodestep {
step_A, step_B, step_C
};
struct base64_encodestate {
enum base64_encodestep step;
char result;
int stepcount;
};
void base64_init_encodestate(struct base64_encodestate *state_in);
char base64_encode_value(char value_in);
int base64_encode_block(const char *plaintext_in, int length_in, char *code_out,
struct base64_encodestate *state_in);
int base64_encode_blockend(char *code_out, struct base64_encodestate *state_in);
enum base64_decodestep {
step_a, step_b, step_c, step_d
};
struct base64_decodestate {
enum base64_decodestep step;
char plainchar;
};
void base64_init_decodestate(struct base64_decodestate *state_in);
signed char base64_decode_value(signed char value_in);
int base64_decode_block(const char *code_in, int length_in, char *plaintext_out,
struct base64_decodestate *state_in);
#endif /* _BASE64_H_ */

View File

@ -8,6 +8,7 @@ lib_libfrr_la_LIBADD = $(LIBCAP) $(UNWIND_LIBS) $(LIBYANG_LIBS) $(LUA_LIB) $(UST
lib_libfrr_la_SOURCES = \
lib/agg_table.c \
lib/atomlist.c \
lib/base64.c \
lib/bfd.c \
lib/buffer.c \
lib/checksum.c \
@ -177,6 +178,7 @@ clippy_scan += \
pkginclude_HEADERS += \
lib/agg_table.h \
lib/atomlist.h \
lib/base64.h \
lib/bfd.h \
lib/bitfield.h \
lib/buffer.h \

View File

@ -19,6 +19,7 @@
#include <zebra.h>
#include "base64.h"
#include "log.h"
#include "lib_errors.h"
#include "northbound.h"
@ -676,6 +677,64 @@ void yang_get_default_string_buf(char *buf, size_t size, const char *xpath_fmt,
xpath);
}
/*
* Primitive type: binary.
*/
struct yang_data *yang_data_new_binary(const char *xpath, const char *value,
size_t len)
{
char *value_str;
struct base64_encodestate s;
int cnt;
char *c;
struct yang_data *data;
value_str = (char *)malloc(len * 2);
base64_init_encodestate(&s);
cnt = base64_encode_block(value, len, value_str, &s);
c = value_str + cnt;
cnt = base64_encode_blockend(c, &s);
c += cnt;
*c = 0;
data = yang_data_new(xpath, value_str);
free(value_str);
return data;
}
size_t yang_dnode_get_binary_buf(char *buf, size_t size,
const struct lyd_node *dnode,
const char *xpath_fmt, ...)
{
const char *canon;
size_t cannon_len;
size_t decode_len;
size_t ret_len;
size_t cnt;
char *value_str;
struct base64_decodestate s;
canon = YANG_DNODE_XPATH_GET_CANON(dnode, xpath_fmt);
cannon_len = strlen(canon);
decode_len = cannon_len;
value_str = (char *)malloc(decode_len);
base64_init_decodestate(&s);
cnt = base64_decode_block(canon, cannon_len, value_str, &s);
ret_len = size > cnt ? cnt : size;
memcpy(buf, value_str, ret_len);
if (size < cnt) {
char xpath[XPATH_MAXLEN];
yang_dnode_get_path(dnode, xpath, sizeof(xpath));
flog_warn(EC_LIB_YANG_DATA_TRUNCATED,
"%s: value was truncated [xpath %s]", __func__,
xpath);
}
free(value_str);
return ret_len;
}
/*
* Primitive type: empty.
*/

View File

@ -118,6 +118,13 @@ extern const char *yang_get_default_string(const char *xpath_fmt, ...);
extern void yang_get_default_string_buf(char *buf, size_t size,
const char *xpath_fmt, ...);
/* binary */
extern struct yang_data *yang_data_new_binary(const char *xpath,
const char *value, size_t len);
extern size_t yang_dnode_get_binary_buf(char *buf, size_t size,
const struct lyd_node *dnode,
const char *xpath_fmt, ...);
/* empty */
extern struct yang_data *yang_data_new_empty(const char *xpath);
extern bool yang_dnode_get_empty(const struct lyd_node *dnode,