From: David Mandelberg <dmand...@bbn.com> Use the schema introduced in the previous commit when inserting ROAs into the database.
WARNING: This is one of a series of commits to use the updated schema. It is not the last in the series, so the code is still broken. addresses [#6] and [#7] --- lib/rpki/cms/roa_general.c | 174 ++++++++++++++++++-------------------- lib/rpki/cms/roa_utils.h | 33 ++++++-- lib/rpki/scmf.h | 4 +- lib/rpki/sqcon.c | 4 +- lib/rpki/sqhl.c | 206 ++++++++++++++++++++++++++++++++++++++++++--- 5 files changed, 306 insertions(+), 115 deletions(-) diff --git a/lib/rpki/cms/roa_general.c b/lib/rpki/cms/roa_general.c index 9c71f92..82d9870 100644 --- a/lib/rpki/cms/roa_general.c +++ b/lib/rpki/cms/roa_general.c @@ -442,125 +442,113 @@ uint32_t roaAS_ID( return (uint32_t)iAS_ID; } -/* - * void roaFree(struct ROA *r) { if (NULL != r) { delete_casn(&(r->self)); - * free((void *)r); } } - */ -static int convertAddr( - int family, - struct ROAIPAddress *ipaddressp, - char *outbuf, - int outbufLth) -{ - memset(outbuf, 0, outbufLth); - uchar abuf[36]; - int addrLth = read_casn(&ipaddressp->address, abuf); - if (family == AF_INET) - { - uint32_t addrVal = 0; - uint32_t xx; - int ii; - if (outbufLth < INET_ADDRSTRLEN + 6) - return ERR_SCM_INVALSZ; - for (ii = 1; ii < addrLth; ii++) - addrVal = (addrVal << 8) + abuf[ii]; - while (ii++ <= (int)sizeof(unsigned int)) - addrVal <<= 8; - xx = htonl(addrVal); - if (!inet_ntop(family, &xx, outbuf, outbufLth)) - return ERR_SCM_INVALIPL; - // prefix length is ((addrLth - 1) * 8) - unused bits - sprintf(&outbuf[strlen(outbuf)], "/%d", ((addrLth - 1) * 8) - abuf[0]); - } - else if (family == AF_INET6) - { - if (outbufLth < INET6_ADDRSTRLEN + 6) - return ERR_SCM_INVALSZ; - uchar addrVal[16]; - memset(addrVal, 0, 16); - memcpy(addrVal, &abuf[1], addrLth - 1); - if (!inet_ntop(family, &addrVal, outbuf, outbufLth)) - return ERR_SCM_INVALIPL; - sprintf(&outbuf[strlen(outbuf)], "/%d", ((addrLth - 1) * 8) - abuf[0]); - } - else - return ERR_SCM_INVALIPB; - - int lth = strlen(outbuf); - if (vsize_casn(&ipaddressp->maxLength)) - { - long j; - read_casn_num(&ipaddressp->maxLength, &j); - sprintf(&outbuf[lth], "(%d)", (int)j); - lth = strlen(outbuf); - } - return lth; -} - -int roaGetIPAddresses( +ssize_t roaGetPrefixes( struct CMS *rp, - char **str) + struct roa_prefix * * prefixes) { struct ROAIPAddrBlocks *addrBlocksp = &rp->content.signedData.encapContentInfo.eContent.roa.ipAddrBlocks; struct ROAIPAddressFamily *famp; - int replysiz = 0, - lth; - char *replyp = NULL; - char tmpbuf[INET6_ADDRSTRLEN + 8]; // to be on safe side - *str = NULL; // in case of failure + + // Actual length of *prefixes + size_t prefixes_length = 0; + + // Allocated length of *prefixes + size_t prefixes_allocated = 16; + + *prefixes = calloc(prefixes_allocated, sizeof(struct roa_prefix)); + if (*prefixes == NULL) + { + return ERR_SCM_NOMEM; + } + + // Buffer for a single IP prefix, stored as a BIT STRING + uint8_t prefix_buf[17]; + for (famp = (struct ROAIPAddressFamily *)member_casn(&addrBlocksp->self, 0); famp; famp = (struct ROAIPAddressFamily *)next_of(&famp->self)) { uchar famtyp[4]; if (read_casn(&famp->addressFamily, famtyp) < 0) + { + free(*prefixes); + *prefixes = NULL; return -1; - int family; - if (famtyp[1] == 1) - family = AF_INET; - else if (famtyp[1] == 2) - family = AF_INET6; + } + + uint_fast8_t prefix_family_length; + switch (famtyp[1]) + { + case 1: + prefix_family_length = 4; + break; + + case 2: + prefix_family_length = 16; + break; + + default: + free(*prefixes); + *prefixes = NULL; + return -1; + } + struct ROAIPAddress *ipaddressp; for (ipaddressp = (struct ROAIPAddress *)member_casn(&famp->addresses.self, 0); ipaddressp; ipaddressp = (struct ROAIPAddress *)next_of(&ipaddressp->self)) { - lth = - convertAddr(family, ipaddressp, tmpbuf, INET6_ADDRSTRLEN + 8); - if (lth < 0) + if (prefixes_length >= prefixes_allocated) { - if (replyp) - free(replyp); - return lth; - } - if (!replysiz) - { // lth + 1 allows for null - if (!(replyp = (char *)calloc(1, lth + 1))) + prefixes_allocated *= 2; + + struct roa_prefix * new_prefixes = realloc( + *prefixes, + prefixes_allocated * sizeof(struct roa_prefix)); + if (new_prefixes == NULL) + { + free(*prefixes); + *prefixes = NULL; return ERR_SCM_NOMEM; - strcpy(replyp, tmpbuf); - replysiz = lth; // size without null + } + *prefixes = new_prefixes; + } + + (*prefixes)[prefixes_length].prefix_family_length = + prefix_family_length; + + int prefix_buflen = + read_casn(&ipaddressp->address, prefix_buf); + memset((*prefixes)[prefixes_length].prefix, 0, + prefix_family_length); + memcpy((*prefixes)[prefixes_length].prefix, + prefix_buf + 1, prefix_buflen - 1); + + (*prefixes)[prefixes_length].prefix_length = + ((prefix_buflen - 1) * 8) - prefix_buf[0]; + + if (vsize_casn(&ipaddressp->maxLength)) + { + long prefix_max_length; + read_casn_num(&ipaddressp->maxLength, + &prefix_max_length); + (*prefixes)[prefixes_length].prefix_max_length = + prefix_max_length; } else { - char *tmpp = (char *)realloc(replyp, replysiz + lth + 3); - if (!tmpp) - { - free(replyp); - return ERR_SCM_NOMEM;; - } - replyp = tmpp; - char *b = &replyp[replysiz]; - *b++ = ','; - *b++ = ' '; - strcpy(b, tmpbuf); - replysiz += lth + 2; // without null + // Default max length is equal to the prefix length + (*prefixes)[prefixes_length].prefix_max_length = + (*prefixes)[prefixes_length].prefix_length; } + + ++prefixes_length; } } - *str = replyp; - return 0; + + return prefixes_length; } int roaGenerateFilter( diff --git a/lib/rpki/cms/roa_utils.h b/lib/rpki/cms/roa_utils.h index 6c4ddc9..740f367 100644 --- a/lib/rpki/cms/roa_utils.h +++ b/lib/rpki/cms/roa_utils.h @@ -165,13 +165,36 @@ int roaGenerateFilter2( struct CMS *r, char **str); -/* - * Fills the IP addresses assigned by a ROA into a multiline string, where - * each line has the form address/prefix_length[/max_prefix_len] +/** + * @brief Represent a prefix from a ROA. + */ +struct roa_prefix +{ + /** + * @brief Length of #prefix, either 4 for IPv4 or 16 for IPv6. + */ + uint8_t prefix_family_length; + + uint8_t prefix[16]; + + uint8_t prefix_length; + + uint8_t prefix_max_length; +}; + +/** + * @brief Extract the prefixes from a ROA. + * + * @param[in] r The ROA. + * @param[out] prefixes On success, *prefixes will be set to point to + * an array of roa prefixes. This value must be free()ed by the + * caller. On failure, *prefixes will be set to NULL. + * @return On success, the number of prefixes. On failure, a negative + * number. */ -int roaGetIPAddresses( +ssize_t roaGetPrefixes( struct CMS *r, - char **str); + struct roa_prefix * * prefixes); /* * This utility function extracts the SKI from a ROA and formats it in the diff --git a/lib/rpki/scmf.h b/lib/rpki/scmf.h index 45aed30..2a2bea5 100644 --- a/lib/rpki/scmf.h +++ b/lib/rpki/scmf.h @@ -131,14 +131,14 @@ extern void freesrchscm( scmsrcha * srch); extern void *unhexify( int strnglen, - char *strng); + char const * strng); extern char *geterrorscm( scmcon * conp); extern char *gettablescm( scmcon * conp); extern char *hexify( int bytelen, - void *bytes, + void const * bytes, int useox); extern int getrowsscm( scmcon * conp); diff --git a/lib/rpki/sqcon.c b/lib/rpki/sqcon.c index 2a08ba8..c835c78 100644 --- a/lib/rpki/sqcon.c +++ b/lib/rpki/sqcon.c @@ -1496,7 +1496,7 @@ int setflagsscm( char *hexify( int bytelen, - void *ptr, + void const * ptr, int useox) { unsigned char *inptr; @@ -1551,7 +1551,7 @@ char *hexify( void *unhexify( int strnglen, - char *strng) + char const * strng) { unsigned char *oot; unsigned int x; diff --git a/lib/rpki/sqhl.c b/lib/rpki/sqhl.c index 5dc019a..b34b8fa 100644 --- a/lib/rpki/sqhl.c +++ b/lib/rpki/sqhl.c @@ -39,6 +39,7 @@ static scmtab *theCertTable = NULL; static scmtab *theROATable = NULL; +static scmtab *theROAPrefixTable = NULL; static scmtab *theCRLTable = NULL; static scmtab *theManifestTable = NULL; static scmtab *theGBRTable = NULL; @@ -89,6 +90,12 @@ static void initTables( LOG(LOG_ERR, "Error finding roa table"); exit(-1); } + theROAPrefixTable = findtablescm(scmp, "ROA_PREFIX"); + if (theROAPrefixTable == NULL) + { + LOG(LOG_ERR, "Error finding roa_prefix table"); + exit(-1); + } theManifestTable = findtablescm(scmp, "MANIFEST"); if (theManifestTable == NULL) { @@ -2965,13 +2972,14 @@ static int add_roa_internal( unsigned int dirid, char *ski, uint32_t asid, - char *ip_addrs, + size_t prefixes_length, + struct roa_prefix const * prefixes, char *sig, unsigned int flags) { unsigned int roa_id = 0; scmkva aone; - scmkv cols[8]; + scmkv cols[7]; char flagn[24]; char asn[24]; char lid[24]; @@ -2979,15 +2987,31 @@ static int add_roa_internal( int idx = 0; int sta; + // Buffer to hold a potentially large INSERT statement. This is + // used to insert multiple rows per statement into + // rpki_roa_prefix. + size_t const multiinsert_len = 32 * 1024; + char * multiinsert = malloc(multiinsert_len); + if (multiinsert == NULL) + { + return ERR_SCM_NOMEM; + } + initTables(scmp); conp->mystat.tabname = "ROA"; // first check for a duplicate signature sta = dupsigscm(scmp, conp, theROATable, sig); if (sta < 0) + { + free(multiinsert); return (sta); + } sta = getmaxidscm(scmp, conp, "local_id", theROATable, &roa_id); if (sta < 0) + { + free(multiinsert); return (sta); + } roa_id++; // fill in insertion structure cols[idx].column = "filename"; @@ -2999,8 +3023,6 @@ static int add_roa_internal( cols[idx++].value = ski; cols[idx].column = "sig"; cols[idx++].value = sig; - cols[idx].column = "ip_addrs"; - cols[idx++].value = ip_addrs; (void)snprintf(asn, sizeof(asn), "%" PRIu32, asid); cols[idx].column = "asn"; cols[idx++].value = asn; @@ -3011,11 +3033,164 @@ static int add_roa_internal( cols[idx].column = "local_id"; cols[idx++].value = lid; aone.vec = &cols[0]; - aone.ntot = 8; + aone.ntot = sizeof(cols)/sizeof(cols[0]); aone.nused = idx; aone.vald = 0; // add the ROA sta = insertscm(conp, theROATable, &aone); + if (sta < 0) + { + free(multiinsert); + return sta; + } + + // Prefix for the insert statement that inserts multiple rows + // into rpki_roa_prefix. + static char const multiinsert_pre[] = + "insert into rpki_roa_prefix " + "(roa_local_id, prefix, prefix_length, prefix_max_length) " + "values "; + static size_t const multiinsert_pre_len = + sizeof(multiinsert_pre) - 1; + + // Index into multiinsert where the next character should be + // written. + size_t multiinsert_idx = 0; + + // String to represent a prefix as VARBINARY in SQL. + char * prefix; + + int snprintf_ret; + + size_t i; + for (i = 0; i < prefixes_length; ++i) + { + if (multiinsert_idx == 0) + { + memcpy(multiinsert, multiinsert_pre, multiinsert_pre_len); + multiinsert_idx += multiinsert_pre_len; + } + + prefix = hexify( + prefixes[i].prefix_family_length, prefixes[i].prefix, + HEXIFY_X); + if (prefix == NULL) + { + sta = ERR_SCM_NOMEM; + goto done; + } + + snprintf_ret = snprintf( + multiinsert + multiinsert_idx, + multiinsert_len - multiinsert_idx, + "(%u, %s, %" PRIu8 ", %" PRIu8 "),", + roa_id, + prefix, + prefixes[i].prefix_length, + prefixes[i].prefix_max_length); + + free(prefix); + prefix = NULL; + + if (snprintf_ret < 0) + { + sta = ERR_SCM_INTERNAL; + goto done; + } + else if ((size_t)snprintf_ret >= + multiinsert_len - multiinsert_idx) + { + // The above write was truncated. + + if (multiinsert_idx == multiinsert_pre_len) + { + // The write was truncated even though it's the first + // prefix in this statement. That's an internal error + // because multiinsert_len is too small. + sta = ERR_SCM_INTERNAL; + goto done; + } + + // Decrement i to ensure this prefix gets inserted + // eventually. + --i; + + // Overwrite the ',' from the previous prefix and + // terminate the statement. + --multiinsert_idx; + multiinsert[multiinsert_idx] = '\0'; + } + else if (i >= prefixes_length - 1) + { + // The write was not truncated, but this is the last + // prefix, so overwrite the ',' from this prefix and + // terminate the statement. + multiinsert_idx += snprintf_ret - 1; + multiinsert[multiinsert_idx] = '\0'; + } + else + { + // The above write was not truncated and this is not the + // last prefix, so attempt to add more prefixes before + // executing the statement. + multiinsert_idx += snprintf_ret; + continue; + } + + // Perform the insert. + sta = statementscm_no_data(conp, multiinsert); + if (sta < 0) + { + LOG(LOG_ERR, + "Error inserting ROA prefixes. SQL query: %s", + multiinsert); + goto done; + } + + // Start the statement at the beginning again with the next + // prefix. + multiinsert_idx = 0; + } + +done: + + if (sta < 0) + { + // There was an error, so delete the ROA we just inserted. + int delete_status; + + delete_status = deletescm(conp, theROATable, &aone); + if (delete_status < 0) + { + LOG(LOG_ERR, + "Error deleting row from rpki_roa: %s (%d)", + err2string(delete_status), delete_status); + } + + // Then delete the prefixes, if they weren't already deleted + // by the foreign key constraints. + scmkva roa_prefixes_aone; + scmkv roa_prefixes_cols[1]; + roa_prefixes_cols[0].column = "roa_local_id"; + roa_prefixes_cols[0].value = lid; + roa_prefixes_aone.vec = &cols[0]; + roa_prefixes_aone.ntot = + sizeof(roa_prefixes_cols)/sizeof(roa_prefixes_cols[0]); + roa_prefixes_aone.nused = roa_prefixes_aone.ntot; + roa_prefixes_aone.vald = 0; + delete_status = + deletescm(conp, theROAPrefixTable, &roa_prefixes_aone); + if (delete_status < 0) + { + LOG(LOG_ERR, + "Error deleting from rpki_roa_prefix with " + "roa_local_id %s: %s (%d)", + lid, err2string(delete_status), delete_status); + } + } + + free(multiinsert); + return (sta); } @@ -3037,8 +3212,9 @@ int add_roa( struct CMS roa; // note: roaFromFile constructs this char ski[60], *sig = NULL, - certfilename[PATH_MAX], - *ip_addrs = NULL; + certfilename[PATH_MAX]; + size_t prefixes_length = 0; + struct roa_prefix * prefixes = NULL; unsigned char *bsig = NULL; int sta, chainOK, @@ -3086,24 +3262,28 @@ int add_roa( if ((sta = verify_roa(conp, &roa, ski, &chainOK)) != 0) break; - // ip_addrs - sta = roaGetIPAddresses(&roa, &ip_addrs); - if (sta != 0) + // prefixes + ssize_t prefixes_ret = roaGetPrefixes(&roa, &prefixes); + if (prefixes_ret < 0) + { break; + } + prefixes_length = prefixes_ret; + sta = addStateToFlags(&flags, chainOK, outfile, outfull, scmp, conp); if (sta != 0) break; // add to database - sta = add_roa_internal(scmp, conp, outfile, id, ski, asid, ip_addrs, - sig, flags); + sta = add_roa_internal(scmp, conp, outfile, id, ski, asid, + prefixes_length, prefixes, sig, flags); if (sta < 0) break; } while (0); // clean up - free(ip_addrs); + free(prefixes); if (sta != 0 && cert_added) (void)delete_object(scmp, conp, certfilename, outdir, outfull, (unsigned int)0); -- 1.9.1 ------------------------------------------------------------------------------ Dive into the World of Parallel Programming. The Go Parallel Website, sponsored by Intel and developed in partnership with Slashdot Media, is your hub for all things parallel software development, from weekly thought leadership blogs to news, videos, case studies, tutorials and more. Take a look and join the conversation now. http://goparallel.sourceforge.net/ _______________________________________________ rpstir-devel mailing list rpstir-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/rpstir-devel