neels has uploaded this change for review. ( https://gerrit.osmocom.org/c/libosmo-pfcp/+/30406 )
Change subject: fix coding of Network Instance IE ......................................................................
fix coding of Network Instance IE
Network instance names should be coded like in DNS, where each label is preceded by a length byte.
Add static functions to converting between dotted and DNS notation. These qualify for moving to libosmocore utils, but giving them a spin here in libosmo-pfcp first (main aim is to speed up the fix now).
Related: SYS#6192 Change-Id: I9d67464ef0f92b0512cfd6e48d203f8828a82a19 --- M src/libosmo-pfcp/pfcp_ies_custom.c M tests/libosmo-pfcp/pfcp_test.ok 2 files changed, 107 insertions(+), 8 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/libosmo-pfcp refs/changes/06/30406/1
diff --git a/src/libosmo-pfcp/pfcp_ies_custom.c b/src/libosmo-pfcp/pfcp_ies_custom.c index 1891902..ac1f6f0 100644 --- a/src/libosmo-pfcp/pfcp_ies_custom.c +++ b/src/libosmo-pfcp/pfcp_ies_custom.c @@ -81,6 +81,97 @@ tlv->len - ((POS) - tlv->val)); \ } while (0)
+/* TODO: this probably qualifies for a libosmocore utils.c function */ +/* A memcpy that can be used by OSMO_STRBUF_APPEND(). */ +static int strncpy_buf(char *buf, size_t buflen, const char *src, size_t len) +{ + size_t cpylen = len; + if (cpylen < SIZE_MAX) + cpylen++; + cpylen = OSMO_MIN(buflen, cpylen); + osmo_strlcpy(buf, src, cpylen); + return len; +} + +/* TODO: this probably qualifies for a libosmocore utils.c function */ +/*! Decode a domain string from a qname (RFC 1035 4.1.2). + * \param[out] buf Output buffer to write the dotted domain name to. + * \param[in] buflen memory available in buf. + * \param[in] qname buffer with length-value pairs for each label (e.g. 0x03 "sip" 0x05 "voice" ...) + * \param[in] qname_len amount of bytes that can be read at most from the memory location that qname points to. + * \returns number of chars that would be written, like snprintf(), negative on error. + */ +static int qname_decode(char *buf, size_t buflen, const uint8_t *qname, size_t qname_len) +{ + struct osmo_strbuf sb = { .buf = buf, .len = buflen }; + const uint8_t *qname_pos = qname; + const uint8_t *qname_end = qname + qname_len; + + /* zero input bytes? */ + if (qname_len < 1) { + if (buflen) + buf[0] = '\0'; + return 0; + } + + while (qname_pos < qname_end) { + size_t len = *qname_pos; + qname_pos++; + + /* Two dots in a row is not allowed */ + if (!len) + return -EINVAL; + /* label must not exceed length of input data */ + if (qname_pos + len > qname_end) + return -EINVAL; + + /* Place a dot before each label, but not at the start. */ + if (sb.chars_needed) + OSMO_STRBUF_PRINTF(sb, "."); + /* Copy label */ + OSMO_STRBUF_APPEND(sb, strncpy_buf, (const char *)qname_pos, len); + qname_pos += len; + } + + return sb.chars_needed; +} + +/* TODO: this probably qualifies for a libosmocore utils.c function */ +/*! Encode a domain string as qname (RFC 1035 4.1.2). + * Encode each label as length-value pairs (e.g. 0x03 "sip" 0x05 "voice" ...). + * No final '\0' character is written. + * \param[out] dst Encode qname to this memory location. + * \param[in] dst_maxlen Memory available at dst. + * \param[in] domain multiple labels separated by dots, e.g. "sip.voice.1234.msisdn". + * \returns nr of bytes written, negative on error. + */ +int qname_encode(uint8_t *dst, size_t dst_maxlen, const char *domain) +{ + uint8_t *dst_pos = dst; + uint8_t *dst_end = dst_pos + dst_maxlen; + const char *pos = domain; + + while (*pos) { + const char *next_dot = strchr(pos, '.'); + size_t len = next_dot ? next_dot - pos : strlen(pos); + + if (len < 1 || len > UINT8_MAX) + return -EINVAL; + + if (dst_pos + 1 + len > dst_end) + return -ENOSPC; + *dst_pos = len; + dst_pos++; + memcpy(dst_pos, pos, len); + dst_pos += len; + + if (!next_dot) + break; + pos = next_dot + 1; + } + return dst_pos - dst; +} + void osmo_pfcp_ie_f_seid_set(struct osmo_pfcp_ie_f_seid *f_seid, uint64_t seid, const struct osmo_sockaddr *remote_addr) { *f_seid = (struct osmo_pfcp_ie_f_seid) { @@ -698,16 +789,24 @@ int osmo_pfcp_dec_network_inst(void *decoded_struct, void *decode_to, const struct osmo_gtlv_load *tlv) { struct osmo_pfcp_ie_network_inst *network_inst = decode_to; - osmo_strlcpy(network_inst->str, (const char *)tlv->val, OSMO_MIN(sizeof(network_inst->str), tlv->len+1)); + int rc; + + rc = qname_decode(network_inst->str, sizeof(network_inst->str), tlv->val, tlv->len); + if (rc < 0) + RETURN_ERROR(rc ? : -EINVAL, "decoding qname (RFC 1035 4.1.2) failed"); return 0; }
int osmo_pfcp_enc_network_inst(struct osmo_gtlv_put *tlv, const void *decoded_struct, const void *encode_from) { const struct osmo_pfcp_ie_network_inst *network_inst = encode_from; - unsigned int l = strlen(network_inst->str); - if (l) - memcpy(msgb_put(tlv->dst, l), network_inst->str, l); + int rc; + + rc = qname_encode(tlv->dst->tail, msgb_tailroom(tlv->dst), network_inst->str); + if (rc <= 0) + RETURN_ERROR(rc ? : -EINVAL, "encoding qname (RFC 1035 4.1.2) from '%s' failed", + (const char *)encode_from); + msgb_put(tlv->dst, rc); return 0; }
diff --git a/tests/libosmo-pfcp/pfcp_test.ok b/tests/libosmo-pfcp/pfcp_test.ok index b8eddb9..02424cd 100644 --- a/tests/libosmo-pfcp/pfcp_test.ok +++ b/tests/libosmo-pfcp/pfcp_test.ok @@ -69,8 +69,8 @@ encoding: SESSION_EST_REQ PFCPv1 SESSION_EST_REQ hdr={seq=7 SEID=0x0} ies={ 'Node ID'=v4:127.0.0.1 'F-SEID'=0x1234567890abcdef,v4:10.9.8.7 'Create PDR'={ { 'PDR ID'=1 'Precedence'=255 'PDI'={ 'Source Interface'=Core 'Network Instance'="foo" 'UE IP Address'=,dst,v4:192.168.0.23 } 'FAR ID'=1 }, { 'PDR ID'=2 'Precedence'=255 'PDI'={ 'Source Interface'=Access 'F-TEID'=CHOOSE-v4 'Network Instance'="bar" } 'Outer Header Removal'=GTP_U_UDP_IPV4 'FAR ID'=2 } } 'Create FAR'={ { 'FAR ID'=1 'Apply Action'=( FORW ) 'Forwarding Parameters'={ 'Destination Interface'=Access 'Outer Header Creation'=( GTP_U_UDP_IPV4 ),TEID:0xabcdef,v4:10.9.8.7 } }, { 'FAR ID'=2 'Apply Action'=( FORW ) 'Forwarding Parameters'={ 'Destination Interface'=Core } } } } osmo_pfcp_msg_encode() rc = 0 -21 32 00 d1 00 00 00 00 00 00 00 00 00 00 07 00 00 3c 00 05 00 7f 00 00 01 00 39 00 0d 02 12 34 56 78 90 ab cd ef 0a 09 08 07 00 01 00 2f 00 38 00 02 00 01 00 1d 00 04 00 00 00 ff 00 02 00 15 00 14 00 01 01 00 16 00 03 66 6f 6f 00 5d 00 05 06 c0 a8 00 17 00 6c 00 04 00 00 00 01 00 01 00 30 00 38 00 02 00 02 00 1d 00 04 00 00 00 ff 00 02 00 11 00 14 00 01 00 00 15 00 01 05 00 16 00 03 62 61 72 00 5f 00 01 00 00 6c 00 04 00 00 00 02 00 03 00 25 00 6c 00 04 00 00 00 01 00 2c 00 02 02 00 00 04 00 13 00 2a 00 01 00 00 54 00 0a 01 00 00 ab cd ef 0a 09 08 07 00 03 00 17 00 6c 00 04 00 00 00 02 00 2c 00 02 02 00 00 04 00 05 00 2a 00 01 01 . -osmo_pfcp_msg_decode_header() rc = 213 +21 32 00 d3 00 00 00 00 00 00 00 00 00 00 07 00 00 3c 00 05 00 7f 00 00 01 00 39 00 0d 02 12 34 56 78 90 ab cd ef 0a 09 08 07 00 01 00 30 00 38 00 02 00 01 00 1d 00 04 00 00 00 ff 00 02 00 16 00 14 00 01 01 00 16 00 04 03 66 6f 6f 00 5d 00 05 06 c0 a8 00 17 00 6c 00 04 00 00 00 01 00 01 00 31 00 38 00 02 00 02 00 1d 00 04 00 00 00 ff 00 02 00 12 00 14 00 01 00 00 15 00 01 05 00 16 00 04 03 62 61 72 00 5f 00 01 00 00 6c 00 04 00 00 00 02 00 03 00 25 00 6c 00 04 00 00 00 01 00 2c 00 02 02 00 00 04 00 13 00 2a 00 01 00 00 54 00 0a 01 00 00 ab cd ef 0a 09 08 07 00 03 00 17 00 6c 00 04 00 00 00 02 00 2c 00 02 02 00 00 04 00 05 00 2a 00 01 01 . +osmo_pfcp_msg_decode_header() rc = 215 rc == msgb_length() osmo_pfcp_msg_decode_tlv() rc = 0 parsed == orig @@ -91,8 +91,8 @@ encoding: SESSION_MOD_REQ PFCPv1 SESSION_MOD_REQ hdr={seq=9 SEID=0x0} ies={ 'Remove PDR'={ { 'PDR ID'=1 } } 'Remove FAR'={ { 'FAR ID'=1 } } 'Create PDR'={ { 'PDR ID'=3 'Precedence'=255 'PDI'={ 'Source Interface'=Access 'F-TEID'=CHOOSE-v4 'Network Instance'="baz" } 'Outer Header Removal'=GTP_U_UDP_IPV4 'FAR ID'=3 } } 'Create FAR'={ { 'FAR ID'=3 'Apply Action'=( FORW ) 'Forwarding Parameters'={ 'Destination Interface'=Access 'Outer Header Creation'=( GTP_U_UDP_IPV4 ),TEID:0xabcdef,v4:10.9.8.7 } } } 'Update PDR'={ { 'PDR ID'=1 'Outer Header Removal'=GTP_U_UDP_IPV4 'PDI'={ 'Source Interface'=Access 'F-TEID'=CHOOSE-v4 'Network Instance'="moo" } 'FAR ID'=1 } } 'Update FAR'={ { 'FAR ID'=1 'Update Forwarding Parameters'={ 'Network Instance'="internet" } } } } osmo_pfcp_msg_encode() rc = 0 -21 34 00 c7 00 00 00 00 00 00 00 00 00 00 09 00 00 0f 00 06 00 38 00 02 00 01 00 10 00 08 00 6c 00 04 00 00 00 01 00 01 00 30 00 38 00 02 00 03 00 1d 00 04 00 00 00 ff 00 02 00 11 00 14 00 01 00 00 15 00 01 05 00 16 00 03 62 61 7a 00 5f 00 01 00 00 6c 00 04 00 00 00 03 00 03 00 25 00 6c 00 04 00 00 00 03 00 2c 00 02 02 00 00 04 00 13 00 2a 00 01 00 00 54 00 0a 01 00 00 ab cd ef 0a 09 08 07 00 09 00 28 00 38 00 02 00 01 00 5f 00 01 00 00 02 00 11 00 14 00 01 00 00 15 00 01 05 00 16 00 03 6d 6f 6f 00 6c 00 04 00 00 00 01 00 0a 00 18 00 6c 00 04 00 00 00 01 00 0b 00 0c 00 16 00 08 69 6e 74 65 72 6e 65 74 . -osmo_pfcp_msg_decode_header() rc = 203 +21 34 00 ca 00 00 00 00 00 00 00 00 00 00 09 00 00 0f 00 06 00 38 00 02 00 01 00 10 00 08 00 6c 00 04 00 00 00 01 00 01 00 31 00 38 00 02 00 03 00 1d 00 04 00 00 00 ff 00 02 00 12 00 14 00 01 00 00 15 00 01 05 00 16 00 04 03 62 61 7a 00 5f 00 01 00 00 6c 00 04 00 00 00 03 00 03 00 25 00 6c 00 04 00 00 00 03 00 2c 00 02 02 00 00 04 00 13 00 2a 00 01 00 00 54 00 0a 01 00 00 ab cd ef 0a 09 08 07 00 09 00 29 00 38 00 02 00 01 00 5f 00 01 00 00 02 00 12 00 14 00 01 00 00 15 00 01 05 00 16 00 04 03 6d 6f 6f 00 6c 00 04 00 00 00 01 00 0a 00 19 00 6c 00 04 00 00 00 01 00 0b 00 0d 00 16 00 09 08 69 6e 74 65 72 6e 65 74 . +osmo_pfcp_msg_decode_header() rc = 206 rc == msgb_length() osmo_pfcp_msg_decode_tlv() rc = 0 parsed == orig