1
0
mirror of https://github.com/bgp/bgpq4.git synced 2024-05-11 05:55:05 +00:00
Files
bgp-bgpq4/bgpq_expander.c

1113 lines
26 KiB
C
Raw Permalink Normal View History

2021-08-17 11:44:14 +00:00
/*
* Copyright (c) 2019-2021 Job Snijders <job@sobornost.net>
* Copyright (c) 2007-2019 Alexandre Snarskii <snar@snar.spb.ru>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
2007-03-22 18:12:32 +00:00
#include <sys/types.h>
#include <sys/socket.h>
2017-06-12 20:11:39 +03:00
#include <sys/select.h>
2007-03-22 18:12:32 +00:00
2015-07-10 18:11:01 +03:00
#include <assert.h>
2015-07-10 20:57:30 +03:00
#include <fcntl.h>
2018-11-30 12:40:25 +03:00
#include <inttypes.h>
2007-03-30 14:05:54 +00:00
#include <ctype.h>
2007-03-22 18:12:32 +00:00
#include <errno.h>
#include <netdb.h>
2018-09-05 14:47:30 +03:00
#include <limits.h>
2007-03-22 18:12:32 +00:00
#include <string.h>
#include <strings.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
2021-08-17 17:26:10 +00:00
#include "extern.h"
2007-03-22 18:12:32 +00:00
#include "sx_report.h"
int debug_expander = 0;
int pipelining = 1;
int expand_special_asn = 0;
static inline int
2021-08-17 19:34:30 +00:00
tentry_cmp(struct sx_tentry *a, struct sx_tentry *b)
{
return strcasecmp(a->text, b->text);
}
2021-08-17 19:34:30 +00:00
RB_GENERATE_STATIC(tentree, sx_tentry, entry, tentry_cmp);
2007-03-22 18:12:32 +00:00
int
2021-08-17 19:34:30 +00:00
bgpq_expander_init(struct bgpq_expander *b, int af)
{
if (!af)
af = AF_INET;
2007-03-22 18:12:32 +00:00
if (!b)
return 0;
memset(b, 0, sizeof(struct bgpq_expander));
2015-06-23 14:56:05 +03:00
b->tree = sx_radix_tree_new(af);
2007-03-22 18:12:32 +00:00
if (!b->tree)
goto fixups;
b->family = af;
b->sources = "";
b->name = "NN";
b->aswidth = 8;
b->asn32s[0] = malloc(8192);
if (!b->asn32s[0]) {
sx_report(SX_FATAL,"Unable to allocate 8192 bytes: %s\n",
strerror(errno));
2008-05-20 15:57:22 +00:00
exit(1);
}
memset(b->asn32s[0], 0, 8192);
b->identify = 1;
b->server = "rr.ntt.net";
b->port = "43";
2007-03-22 18:12:32 +00:00
2018-12-10 05:26:33 -06:00
// b->wq = STAILQ_HEAD_INITIALZIER(b->wq);
// b->rq = STAILQ_HEAD_INITIALZIER(b->rq);
// b->rsets = STAILQ_HEAD_INITIALZIER(b->rsets);
// b->macroses = STAILQ_HEAD_INITIALZIER(b->macroses);
2015-07-10 20:57:30 +03:00
STAILQ_INIT(&b->wq);
STAILQ_INIT(&b->rq);
STAILQ_INIT(&b->rsets);
STAILQ_INIT(&b->macroses);
2015-07-10 20:57:30 +03:00
2007-03-22 18:12:32 +00:00
return 1;
2007-03-22 18:12:32 +00:00
fixups:
if (b->tree)
sx_radix_tree_freeall(b->tree);
b->tree = NULL;
2007-03-22 18:12:32 +00:00
free(b);
2007-03-22 18:12:32 +00:00
return 0;
}
2007-03-22 18:12:32 +00:00
int
2021-08-17 19:34:30 +00:00
bgpq_expander_add_asset(struct bgpq_expander *b, char *as)
{
2021-08-17 19:34:30 +00:00
struct sx_slentry *le;
if (!b || !as)
return 0;
le = sx_slentry_new(as);
STAILQ_INSERT_TAIL(&b->macroses, le, next);
2007-03-22 18:12:32 +00:00
return 1;
}
2007-03-22 18:12:32 +00:00
int
2021-08-17 19:34:30 +00:00
bgpq_expander_add_rset(struct bgpq_expander *b, char *rs)
{
2021-08-17 19:34:30 +00:00
struct sx_slentry *le;
if (!b || !rs)
return 0;
le = sx_slentry_new(rs);
if (!le)
return 0;
STAILQ_INSERT_TAIL(&b->rsets, le, next);
2008-06-02 11:32:25 +00:00
return 1;
}
2008-06-02 11:32:25 +00:00
2021-08-17 19:34:30 +00:00
static int
bgpq_expander_add_already(struct bgpq_expander *b, char *rs)
2015-07-10 16:01:22 +03:00
{
2021-08-17 19:34:30 +00:00
struct sx_tentry *le, lkey;
lkey.text = rs;
if (RB_FIND(tentree, &b->already, &lkey))
return 1;
le = sx_tentry_new(rs);
RB_INSERT(tentree, &b->already, le);
return 1;
}
int
2021-08-17 19:34:30 +00:00
bgpq_expander_add_stop(struct bgpq_expander *b, char *rs)
{
2021-08-17 19:34:30 +00:00
struct sx_tentry *le, lkey;
lkey.text = rs;
if (RB_FIND(tentree, &b->stoplist, &lkey))
return 1;
le = sx_tentry_new(rs);
RB_INSERT(tentree, &b->stoplist, le);
2015-07-10 16:01:22 +03:00
return 1;
}
2015-07-10 16:01:22 +03:00
2007-03-22 18:12:32 +00:00
int
2021-08-17 19:34:30 +00:00
bgpq_expander_add_as(struct bgpq_expander *b, char *as)
{
2021-08-17 19:34:30 +00:00
char *eoa;
uint32_t asn1 = 0, asn2 = 0;
uint32_t asno = 0;
2007-03-22 18:12:32 +00:00
if (!b || !as)
return 0;
2007-03-22 18:12:32 +00:00
asno = strtoul(as + 2, &eoa, 10);
if (eoa && *eoa != 0) {
sx_report(SX_ERROR,"Invalid symbol in AS number: '%c' in %s\n",
*eoa, as);
2007-03-22 18:12:32 +00:00
return 0;
}
if (asno > 65535) {
asn1 = asno / 65536;
asn2 = asno % 65536;
} else
asn1 = asno;
if (!expand_special_asn &&
((asno >= 4200000000ul) || (asno >= 64496 && asno <= 65551)))
2007-03-22 18:12:32 +00:00
return 0;
if (!b->asn32s[asn1]) {
b->asn32s[asn1] = malloc(8192);
if (!b->asn32s[asn1]) {
sx_report(SX_FATAL, "Unable to allocate 8192 "
"bytes: %s. Unable to add asn32 %s to "
" future expansion\n", strerror(errno), as);
return 0;
}
memset(b->asn32s[asn1], 0, 8192);
}
if (asno > 65535)
b->asn32s[asn1][asn2 / 8] |= (0x80 >> (asn2 % 8));
else
b->asn32s[0][asn1 / 8] |= (0x80 >> (asn1 % 8));
2007-03-22 18:12:32 +00:00
return 1;
}
2007-03-22 18:12:32 +00:00
int
2021-08-17 19:34:30 +00:00
bgpq_expander_add_prefix(struct bgpq_expander *b, char *prefix)
{
2018-12-10 05:26:33 -06:00
struct sx_prefix *p = sx_prefix_alloc(NULL);
2021-08-17 19:34:30 +00:00
if (!sx_prefix_parse(p, 0, prefix)) {
sx_report(SX_ERROR, "Unable to parse prefix %s\n", prefix);
2007-03-22 18:12:32 +00:00
return 0;
} else if (p->family != b->family) {
SX_DEBUG(debug_expander, "Ignoring prefix %s with wrong "
"address family\n", prefix);
2008-06-02 11:32:25 +00:00
return 0;
}
if (b->maxlen && p->masklen>b->maxlen) {
SX_DEBUG(debug_expander, "Ignoring prefix %s: masklen %i > max"
" masklen %u\n", prefix, p->masklen, b->maxlen);
return 0;
}
2021-08-17 10:06:13 +00:00
sx_radix_tree_insert(b->tree, p);
if (p)
sx_prefix_destroy(p);
return 1;
}
2007-03-22 18:12:32 +00:00
int
2021-08-17 19:34:30 +00:00
bgpq_expander_add_prefix_range(struct bgpq_expander *b, char *prefix)
{
return sx_prefix_range_parse(b->tree, b->family, b->maxlen, prefix);
}
2021-08-17 19:34:30 +00:00
static int
bgpq_expanded_macro(char *as, struct bgpq_expander *ex,
struct bgpq_request *req)
{
bgpq_expander_add_as(ex, as);
2007-03-22 18:12:32 +00:00
return 1;
}
2007-03-22 18:12:32 +00:00
2021-08-17 19:34:30 +00:00
struct bgpq_request *bgpq_pipeline(struct bgpq_expander *b,
int (*callback)(char*, struct bgpq_expander *b, struct bgpq_request *req),
void *udata, char *fmt, ...);
int bgpq_expand_irrd(struct bgpq_expander *b,
int (*callback)(char*, struct bgpq_expander *b, struct bgpq_request *req),
void *udata, char *fmt, ...);
2015-07-10 16:01:22 +03:00
2021-08-17 19:34:30 +00:00
static int
bgpq_expanded_macro_limit(char *as, struct bgpq_expander *b,
struct bgpq_request *req)
2015-07-10 16:01:22 +03:00
{
2015-07-12 16:42:50 +03:00
if (!strncasecmp(as, "AS-", 3) || strchr(as, '-') || strchr(as, ':')) {
struct sx_tentry tkey = { .text = as };
if (RB_FIND(tentree, &b->already, &tkey)) {
SX_DEBUG(debug_expander>2, "%s is already expanding, "
"ignore\n", as);
return 0;
}
if (RB_FIND(tentree, &b->stoplist, &tkey)) {
SX_DEBUG(debug_expander>2, "%s is in the stoplist, "
"ignore\n", as);
return 0;
}
if (!b->maxdepth ||
(b->cdepth + 1 < b->maxdepth &&
req->depth + 1 < b->maxdepth)) {
bgpq_expander_add_already(b, as);
2015-07-10 16:01:22 +03:00
if (pipelining) {
2021-08-17 19:34:30 +00:00
struct bgpq_request *req1 = bgpq_pipeline(b,
bgpq_expanded_macro_limit, NULL, "!i%s\n",
as);
2015-07-12 16:42:50 +03:00
req1->depth = req->depth+1;
2015-07-10 16:01:22 +03:00
} else {
2015-07-12 16:42:50 +03:00
b->cdepth++;
bgpq_expand_irrd(b, bgpq_expanded_macro_limit,
NULL, "!i%s\n", as);
2015-07-12 16:42:50 +03:00
b->cdepth--;
}
2015-07-10 16:01:22 +03:00
} else {
SX_DEBUG(debug_expander>2, "ignoring %s at depth %i\n",
as,
b->cdepth ? (b->cdepth + 1) : (req->depth + 1));
}
} else if (!strncasecmp(as, "AS", 2)) {
2015-07-13 14:36:13 +03:00
struct sx_tentry tkey = { .text = as };
2015-07-13 14:36:13 +03:00
if (RB_FIND(tentree, &b->stoplist, &tkey)) {
SX_DEBUG(debug_expander > 2,
"%s is in the stoplist, ignore\n", as);
2015-07-13 14:36:13 +03:00
return 0;
}
if (bgpq_expander_add_as(b, as)) {
SX_DEBUG(debug_expander > 2, ".. added asn %s\n", as);
2015-07-10 16:01:22 +03:00
} else {
SX_DEBUG(debug_expander, ".. some error adding as %s "
"(in response to %s)\n", as, req->request);
}
} else if (!strcasecmp(as, "ANY"))
return 0;
else
sx_report(SX_ERROR, "unexpected object '%s' in "
"expanded_macro_limit (in response to %s)\n", as,
req->request);
2015-07-10 16:01:22 +03:00
return 1;
}
2015-07-10 16:01:22 +03:00
2021-08-17 19:34:30 +00:00
static int
bgpq_expanded_prefix(char *as, struct bgpq_expander *ex,
struct bgpq_request *req __attribute__((unused)))
{
2021-08-17 19:34:30 +00:00
char *d = strchr(as, '^');
if (!d)
bgpq_expander_add_prefix(ex, as);
else
bgpq_expander_add_prefix_range(ex, as);
2007-03-22 18:12:32 +00:00
return 1;
}
2007-03-22 18:12:32 +00:00
2021-08-17 19:34:30 +00:00
static int
bgpq_expanded_v6prefix(char *prefix, struct bgpq_expander * ex,
struct bgpq_request* req)
{
2021-08-17 19:34:30 +00:00
char *d = strchr(prefix, '^');
2018-08-14 12:42:18 +03:00
if (!d)
bgpq_expander_add_prefix(ex, prefix);
2018-08-14 12:42:18 +03:00
else
bgpq_expander_add_prefix_range(ex, prefix);
2007-03-30 14:05:54 +00:00
return 1;
}
2007-03-30 14:05:54 +00:00
2021-08-17 19:34:30 +00:00
int bgpq_pipeline_dequeue(int fd, struct bgpq_expander *b);
2015-07-10 20:57:30 +03:00
static struct bgpq_request*
2021-08-17 19:34:30 +00:00
bgpq_request_alloc(char *request, int (*callback)(char*, struct bgpq_expander*,
struct bgpq_request*), void* udata)
2015-07-10 20:57:30 +03:00
{
struct bgpq_request* bp = malloc(sizeof(struct bgpq_request));
2015-07-10 20:57:30 +03:00
if (!bp)
return NULL;
2015-07-10 20:57:30 +03:00
memset(bp, 0, sizeof(struct bgpq_request));
bp->request = strdup(request);
bp->offset = 0;
bp->size = strlen(bp->request);
bp->callback = callback;
bp->udata = udata;
2015-07-10 20:57:30 +03:00
return bp;
}
2015-06-23 14:56:05 +03:00
2015-07-12 16:42:50 +03:00
static void
bgpq_request_free(struct bgpq_request* req)
{
if (req->request)
free(req->request);
2015-07-12 16:42:50 +03:00
free(req);
}
2015-07-12 16:42:50 +03:00
struct bgpq_request*
2021-08-17 19:34:30 +00:00
bgpq_pipeline(struct bgpq_expander *b,
int (*callback)(char*, struct bgpq_expander*, struct bgpq_request*),
2021-08-17 19:34:30 +00:00
void* udata, char *fmt, ...)
{
2008-05-19 13:33:32 +00:00
char request[128];
2015-07-12 18:57:22 +03:00
int ret;
struct bgpq_request* bp = NULL;
2008-05-19 13:33:32 +00:00
va_list ap;
va_start(ap, fmt);
vsnprintf(request, sizeof(request), fmt, ap);
2008-05-19 13:33:32 +00:00
va_end(ap);
2015-07-10 20:57:30 +03:00
SX_DEBUG(debug_expander,"expander: sending %s", request);
2007-03-30 14:05:54 +00:00
2015-07-10 20:57:30 +03:00
bp = bgpq_request_alloc(request, callback, udata);
if (!bp) {
sx_report(SX_FATAL,"Unable to allocate %lu bytes: %s\n",
(unsigned long)sizeof(struct bgpq_request),
strerror(errno));
2015-07-10 16:57:46 +03:00
exit(1);
}
2015-07-10 20:57:30 +03:00
if (STAILQ_EMPTY(&b->wq)) {
ret = write(b->fd, request, bp->size);
2015-07-12 18:57:22 +03:00
if (ret < 0) {
if (errno == EAGAIN) {
STAILQ_INSERT_TAIL(&b->wq, bp, next);
return bp;
}
sx_report(SX_FATAL, "Error writing request: %s\n",
strerror(errno));
}
2015-07-12 16:42:50 +03:00
bp->offset=ret;
2015-07-10 20:57:30 +03:00
if (ret == bp->size) {
STAILQ_INSERT_TAIL(&b->rq, bp, next);
} else {
STAILQ_INSERT_TAIL(&b->wq, bp, next);
}
2015-07-10 20:57:30 +03:00
} else
STAILQ_INSERT_TAIL(&b->wq, bp, next);
2015-07-10 16:57:46 +03:00
2015-07-12 16:42:50 +03:00
return bp;
}
2008-05-19 13:33:32 +00:00
2018-09-05 14:47:30 +03:00
static void
2021-08-17 19:34:30 +00:00
bgpq_expander_invalidate_asn(struct bgpq_expander *b, const char *q)
2018-09-05 14:47:30 +03:00
{
2018-11-30 12:40:25 +03:00
if (!strncmp(q, "!gas", 4) || !strncmp(q, "!6as", 4)) {
2021-08-17 19:34:30 +00:00
char *eptr;
2018-11-30 12:40:25 +03:00
unsigned long asn = strtoul(q+4, &eptr, 10), asn0, asn1 = 0;
if (!asn || asn == ULONG_MAX || asn >= 4294967295
|| (eptr && *eptr != '\n')) {
sx_report(SX_ERROR, "some problem invalidating asn"
" %s\n", q);
2018-11-30 12:40:25 +03:00
return;
}
2018-11-30 12:40:25 +03:00
asn1 = asn % 65536;
asn0 = asn / 65536;
if (!b->asn32s[asn0] ||
2021-08-17 10:06:13 +00:00
!(b->asn32s[asn0][asn1/8] & (0x80 >> (asn1 % 8)))) {
sx_report(SX_NOTICE, "strange, invalidating inactive "
"asn %lu(%s)\n", asn, q);
2018-11-30 12:40:25 +03:00
} else {
b->asn32s[asn0][asn1 / 8] &= ~(0x80 >> (asn1 % 8));
}
}
}
2018-09-05 14:47:30 +03:00
2015-07-10 20:57:30 +03:00
static void
2021-08-17 19:34:30 +00:00
bgpq_write(struct bgpq_expander *b)
2015-07-10 20:57:30 +03:00
{
while(!STAILQ_EMPTY(&b->wq)) {
struct bgpq_request* req = STAILQ_FIRST(&b->wq);
int ret = write(b->fd, req->request+req->offset,
req->size-req->offset);
2015-07-12 18:57:22 +03:00
if (ret < 0) {
if (errno == EAGAIN)
return;
sx_report(SX_FATAL, "error writing data: %s\n",
strerror(errno));
}
2015-07-10 20:57:30 +03:00
if (ret == req->size - req->offset) {
/* this request was dequeued */
STAILQ_REMOVE_HEAD(&b->wq, next);
STAILQ_INSERT_TAIL(&b->rq, req, next);
} else {
req->offset += ret;
break;
}
}
}
2008-05-19 13:33:32 +00:00
static int
2021-08-17 19:34:30 +00:00
bgpq_selread(struct bgpq_expander *b, char *buffer, int size)
{
fd_set rfd, wfd;
int ret;
repeat:
FD_ZERO(&rfd);
2015-07-12 16:42:50 +03:00
FD_SET(b->fd, &rfd);
FD_ZERO(&wfd);
if (!STAILQ_EMPTY(&b->wq))
2015-07-12 16:42:50 +03:00
FD_SET(b->fd, &wfd);
ret = select(b->fd + 1, &rfd, &wfd, NULL, NULL);
if (ret == 0)
sx_report(SX_FATAL, "select failed\n");
else if (ret == -1 && errno == EINTR)
goto repeat;
else if (ret == -1)
sx_report(SX_FATAL, "select error %i: %s\n", errno,
strerror(errno));
2015-07-12 16:42:50 +03:00
if (!STAILQ_EMPTY(&b->wq) && FD_ISSET(b->fd, &wfd))
bgpq_write(b);
2015-07-12 16:42:50 +03:00
if (FD_ISSET(b->fd, &rfd))
return read(b->fd, buffer, size);
goto repeat;
}
2021-08-17 19:34:30 +00:00
static int
bgpq_read(struct bgpq_expander *b)
{
2015-07-10 20:57:30 +03:00
static char response[256];
static int off = 0;
if (!STAILQ_EMPTY(&b->wq))
2015-07-12 16:42:50 +03:00
bgpq_write(b);
2015-07-10 20:57:30 +03:00
while(!STAILQ_EMPTY(&b->rq)) {
struct bgpq_request* req = STAILQ_FIRST(&b->rq);
SX_DEBUG(debug_expander > 2, "waiting for answer to %s,"
"init %i '%.*s'\n", req->request, off, off, response);
2015-07-10 20:57:30 +03:00
int ret = 0;
2021-08-17 19:34:30 +00:00
char *cres;
2015-07-10 20:57:30 +03:00
if ((cres=strchr(response, '\n')) != NULL)
2015-07-10 20:57:30 +03:00
goto have;
2015-07-10 20:57:30 +03:00
repeat:
ret = bgpq_selread(b, response + off, sizeof(response) - off);
2015-07-10 20:57:30 +03:00
if (ret < 0) {
if (errno == EAGAIN)
goto repeat;
sx_report(SX_FATAL,"Error reading data from IRRd: "
"%s (dequeue)\n", strerror(errno));
2015-07-10 20:57:30 +03:00
} else if (ret == 0) {
sx_report(SX_FATAL,"EOF from IRRd (dequeue)\n");
}
2015-07-10 20:57:30 +03:00
off += ret;
2008-05-19 13:33:32 +00:00
if (!(cres = strchr(response, '\n')))
2015-07-10 20:57:30 +03:00
goto repeat;
2015-07-10 20:57:30 +03:00
have:
SX_DEBUG(debug_expander > 5, "got response of %.*s\n", off,
response);
if (response[0] == 'A') {
2021-08-17 19:34:30 +00:00
char *eon, *c;
unsigned long offset = 0;
unsigned long togot = strtoul(response + 1, &eon, 10);
char *recvbuffer = malloc(togot + 2);
if (!recvbuffer) {
sx_report(SX_FATAL, "error allocating %lu "
"bytes: %s\n", togot + 2, strerror(errno));
}
memset(recvbuffer,0,togot+2);
2008-05-19 13:33:32 +00:00
if (!eon || *eon != '\n') {
sx_report(SX_ERROR,"A-code finished with wrong"
" char '%c'(%s)\n", eon ? *eon : '0',
response);
2008-05-19 13:33:32 +00:00
exit(1);
}
2015-07-10 20:57:30 +03:00
2021-08-17 19:34:30 +00:00
if ((unsigned)(off - ((eon + 1) - response)) > togot) {
// full response and more data is already in buffer
memcpy(recvbuffer, eon + 1, togot);
offset = togot;
memmove(response, eon + 1 + togot,
off - ((eon + 1) - response) - togot);
off -= togot + ((eon + 1) - response);
memset(response + off, 0,
sizeof(response) - off);
} else {
/* response is not yet fully buffered */
memcpy(recvbuffer, eon + 1,
off - ((eon + 1) - response));
offset = off - ((eon+1) - response);
memset(response, 0, sizeof(response));
off = 0;
}
2015-07-10 20:57:30 +03:00
2021-08-17 19:34:30 +00:00
SX_DEBUG(debug_expander > 5,
"starting read with ready '%.*s', waiting for "
2021-08-17 19:34:30 +00:00
"%lu\n", (int)offset, recvbuffer, togot - offset);
if (off > 0)
2015-07-10 20:57:30 +03:00
goto have3;
if (offset == togot)
goto reread2;
2015-07-10 20:57:30 +03:00
reread:
2021-08-17 19:34:30 +00:00
ret = bgpq_selread(b, recvbuffer + offset, togot - offset);
2015-07-10 20:57:30 +03:00
if (ret < 0) {
if (errno == EAGAIN)
goto reread;
sx_report(SX_FATAL,"Error reading IRRd: %s "
"(dequeue, result)\n", strerror(errno));
2015-07-10 20:57:30 +03:00
} else if (ret == 0) {
sx_report(SX_FATAL,"EOF from IRRd (dequeue, "
"result)\n");
}
SX_DEBUG(debug_expander > 5,
"Read1: got '%.*s'\n", ret,
recvbuffer + offset);
offset += ret;
if (offset < togot) {
SX_DEBUG(debug_expander>5, "expected %lu, got "
"%lu expanding %s", togot,
strlen(recvbuffer), req->request);
2015-07-10 20:57:30 +03:00
goto reread;
}
2015-07-10 20:57:30 +03:00
reread2:
ret = bgpq_selread(b, response + off,
sizeof(response) - off);
2015-07-10 20:57:30 +03:00
if (ret < 0) {
if (errno == EAGAIN)
goto reread2;
sx_report(SX_FATAL,"Error reading IRRd: %s "
"(dequeue,final)\n", strerror(errno));
2015-07-10 20:57:30 +03:00
} else if (ret == 0) {
sx_report(SX_FATAL,"EOF from IRRd (dequeue,"
"final)\n");
}
SX_DEBUG(debug_expander > 5,
"Read2: got '%.*s'\n", ret, response + off);
off += ret;
2015-07-10 20:57:30 +03:00
have3:
if (!(cres = strchr(response, '\n')))
goto reread2;
SX_DEBUG(debug_expander>=3,"Got %s (%lu bytes of %lu) "
"in response to %sfinal code: %.*s", recvbuffer,
strlen(recvbuffer), togot, req->request,
off, response);
2008-05-19 13:33:32 +00:00
for (c = recvbuffer; c < recvbuffer + togot;) {
2008-05-19 13:33:32 +00:00
size_t spn=strcspn(c," \n");
if (spn)
c[spn] = 0;
if (c[0] == 0)
break;
2015-07-12 16:42:50 +03:00
req->callback(c, b, req);
c += spn+1;
}
assert(c == recvbuffer + togot);
memset(recvbuffer, 0, togot + 2);
2015-07-10 16:57:46 +03:00
free(recvbuffer);
} else if (response[0] == 'C') {
2008-05-19 13:33:32 +00:00
/* No data */
SX_DEBUG(debug_expander,"No data expanding %s\n",
req->request);
if (b->validate_asns)
bgpq_expander_invalidate_asn(b, req->request);
} else if (response[0] == 'D') {
2008-05-19 13:33:32 +00:00
/* .... */
2015-07-10 20:57:30 +03:00
SX_DEBUG(debug_expander,"Key not found expanding %s\n",
req->request);
if (b->validate_asns)
bgpq_expander_invalidate_asn(b, req->request);
} else if (response[0] == 'E') {
2015-07-10 20:57:30 +03:00
sx_report(SX_ERROR, "Multiple keys expanding %s: %s\n",
req->request, response);
} else if ( response[0] == 'F') {
2015-07-10 20:57:30 +03:00
sx_report(SX_ERROR, "Error expanding %s: %s\n",
req->request, response);
} else {
2015-07-10 18:11:01 +03:00
sx_report(SX_ERROR,"Wrong reply: %s to %s\n", response,
req->request);
2015-07-10 18:11:01 +03:00
exit(1);
}
memmove(response, cres + 1, off - ((cres + 1) - response));
off -= (cres+1) - response;
memset(response + off, 0, sizeof(response) - off);
SX_DEBUG(debug_expander > 5,
"fixed response of %i, %.*s\n", off, off, response);
2008-05-19 13:33:32 +00:00
2015-07-10 20:57:30 +03:00
STAILQ_REMOVE_HEAD(&b->rq, next);
2008-05-19 13:33:32 +00:00
b->piped--;
2015-07-12 16:42:50 +03:00
bgpq_request_free(req);
}
2008-05-19 13:33:32 +00:00
return 0;
}
2007-03-30 14:05:54 +00:00
2007-03-22 18:12:32 +00:00
int
2021-08-17 19:34:30 +00:00
bgpq_expand_irrd(struct bgpq_expander *b,
int (*callback)(char*, struct bgpq_expander*, struct bgpq_request* ),
2021-08-17 19:34:30 +00:00
void* udata, char *fmt, ...)
{
2021-08-17 19:34:30 +00:00
char request[128], response[128];
va_list ap;
size_t ret;
int off = 0;
struct bgpq_request *req;
2007-03-22 18:12:32 +00:00
2021-08-17 10:06:13 +00:00
va_start(ap, fmt);
vsnprintf(request, sizeof(request), fmt, ap);
2007-03-22 18:12:32 +00:00
va_end(ap);
2015-07-12 16:42:50 +03:00
req = bgpq_request_alloc(request, callback, udata);
SX_DEBUG(debug_expander, "expander: sending '%s'\n", request);
2015-07-12 16:42:50 +03:00
ret=write(b->fd, request, strlen(request));
if (ret != strlen(request)) {
2021-08-17 19:34:30 +00:00
sx_report(SX_FATAL,"Partial write to IRRd, only %lu bytes "
"written: %s\n", ret, strerror(errno));
2007-03-22 18:12:32 +00:00
exit(1);
}
memset(response, 0, sizeof(response));
2015-07-10 20:57:30 +03:00
repeat:
2015-07-12 16:42:50 +03:00
ret = bgpq_selread(b, response+off, sizeof(response)-off);
2015-07-10 20:57:30 +03:00
if (ret < 0) {
sx_report(SX_ERROR, "Error reading IRRd: %s\n",
strerror(errno));
2015-07-10 20:57:30 +03:00
exit(1);
} else if (ret == 0) {
sx_report(SX_FATAL, "EOF reading IRRd\n");
2007-03-22 18:12:32 +00:00
exit(1);
}
off += ret;
2015-07-10 20:57:30 +03:00
if (strchr(response, '\n') == NULL)
2015-07-10 20:57:30 +03:00
goto repeat;
SX_DEBUG(debug_expander > 2, "expander: initially got %lu bytes, "
"'%s'\n", (unsigned long)strlen(response), response);
if (response[0] == 'A') {
2021-08-17 19:34:30 +00:00
char *eon, *c;
long togot = strtoul(response+1, &eon, 10);
char *recvbuffer = malloc(togot + 2);
int offset = 0;
if (!recvbuffer) {
sx_report(SX_FATAL, "Error allocating %lu bytes: %s\n",
togot + 2, strerror(errno));
}
if (eon && *eon != '\n') {
sx_report(SX_ERROR,"A-code finised with wrong char "
2021-08-17 10:06:13 +00:00
"'%c' (%s)\n", *eon, response);
2007-03-22 18:12:32 +00:00
exit(1);
}
if (off - ((eon + 1)-response) > togot) {
memcpy(recvbuffer, eon+1, togot);
offset = togot;
memmove(response, eon + 1 + togot,
off - ((eon + 1) - response) - togot);
off -= togot + ((eon + 1) - response);
memset(response+off, 0, sizeof(response) - off);
} else {
memcpy(recvbuffer, eon + 1,
off - ((eon + 1) - response));
offset = off - ((eon + 1) - response);
memset(response, 0, sizeof(response));
off = 0;
}
if (off > 0)
goto have3;
if (offset == togot)
goto reread2;
2015-07-10 20:57:30 +03:00
reread:
ret = bgpq_selread(b, recvbuffer + offset, togot - offset);
2015-07-10 20:57:30 +03:00
if (ret == 0) {
sx_report(SX_FATAL,"EOF from IRRd (expand,result)\n");
} else if (ret < 0) {
sx_report(SX_FATAL,"Error reading IRRd: %s "
"(expand,result)\n", strerror(errno));
}
offset += ret;
if (offset < togot)
2015-07-10 20:57:30 +03:00
goto reread;
reread2:
ret = bgpq_selread(b, response+off, sizeof(response) - off);
2015-07-10 20:57:30 +03:00
if (ret < 0) {
sx_report(SX_FATAL, "error reading IRRd: %s\n",
strerror(errno));
2015-07-10 20:57:30 +03:00
exit(1);
} else if (ret == 0) {
sx_report(SX_FATAL, "eof reading IRRd\n");
2015-07-10 16:01:22 +03:00
exit(1);
}
off += ret;
have3:
if (!strchr(response, '\n'))
goto reread2;
2015-07-10 20:57:30 +03:00
SX_DEBUG(debug_expander>2,"expander: final reply of %lu bytes,"
" %.*sreturn code %.*s",
(unsigned long)strlen(recvbuffer), offset, recvbuffer, off,
response);
for (c = recvbuffer; c < recvbuffer + togot;) {
size_t spn = strcspn(c, " \n");
if (spn)
c[spn] = 0;
if (c[0] == 0)
break;
if (callback)
callback(c, b, req);
c += spn + 1;
}
memset(recvbuffer, 0, togot + 2);
free(recvbuffer);
} else if (response[0] == 'C') {
2007-03-22 18:12:32 +00:00
/* no data */
if (b->validate_asns)
bgpq_expander_invalidate_asn(b, request);
} else if (response[0] == 'D') {
2007-03-22 18:12:32 +00:00
/* ... */
if (b->validate_asns)
bgpq_expander_invalidate_asn(b, request);
} else if (response[0] == 'E') {
2007-03-22 18:12:32 +00:00
/* XXXXXX */
} else if (response[0] == 'F') {
2007-03-22 18:12:32 +00:00
/* XXXXXX */
} else {
2015-07-10 16:01:22 +03:00
sx_report(SX_ERROR,"Wrong reply: %s\n", response);
2007-03-22 18:12:32 +00:00
exit(0);
}
2015-07-12 16:42:50 +03:00
bgpq_request_free(req);
2007-03-22 18:12:32 +00:00
return 0;
}
2007-03-22 18:12:32 +00:00
int
2021-08-17 19:34:30 +00:00
bgpq_expand(struct bgpq_expander *b)
{
2021-08-17 19:34:30 +00:00
int fd = -1, err, ret, aquery = 0;
struct sx_slentry *mc;
struct addrinfo hints, *res = NULL, *rp;
struct linger sl;
2019-08-15 20:11:03 +03:00
sl.l_onoff = 1;
sl.l_linger = 5;
2007-03-22 18:12:32 +00:00
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_socktype = SOCK_STREAM;
err=getaddrinfo(b->server, b->port, &hints, &res);
2007-03-22 18:12:32 +00:00
if (err) {
sx_report(SX_ERROR,"Unable to resolve %s: %s\n", b->server,
gai_strerror(err));
2007-03-22 18:12:32 +00:00
exit(1);
}
2007-03-22 18:12:32 +00:00
for (rp=res; rp; rp = rp->ai_next) {
fd = socket(rp->ai_family, rp->ai_socktype, 0);
if (fd == -1) {
2021-08-17 10:06:13 +00:00
if (errno == EPROTONOSUPPORT || errno == EAFNOSUPPORT)
continue;
sx_report(SX_ERROR,"Unable to create socket: %s\n",
strerror(errno));
2007-03-22 18:12:32 +00:00
exit(1);
}
if (setsockopt(fd, SOL_SOCKET, SO_LINGER, &sl,
sizeof(struct linger))) {
sx_report(SX_ERROR,"Unable to set linger on socket: "
"%s\n", strerror(errno));
2019-08-15 20:11:03 +03:00
close(fd);
exit(1);
}
err = connect(fd, rp->ai_addr, rp->ai_addrlen);
if (err) {
2007-03-22 18:12:32 +00:00
close(fd);
fd = -1;
2007-03-22 18:12:32 +00:00
continue;
}
err = sx_maxsockbuf(fd, SO_SNDBUF);
if (err > 0) {
SX_DEBUG(debug_expander, "Acquired sendbuf of %i "
"bytes\n", err);
2015-06-23 14:56:05 +03:00
} else {
close(fd);
fd = -1;
2015-06-23 14:56:05 +03:00
continue;
}
2007-03-22 18:12:32 +00:00
break;
}
2007-03-22 18:12:32 +00:00
freeaddrinfo(res);
if (fd == -1) {
2007-03-22 18:12:32 +00:00
/* all our attempts to connect failed */
2008-12-19 17:41:06 +00:00
sx_report(SX_ERROR,"All attempts to connect %s failed, last"
" error: %s\n", b->server, strerror(errno));
2007-03-22 18:12:32 +00:00
exit(1);
}
2015-06-23 14:56:05 +03:00
2015-07-12 16:42:50 +03:00
b->fd = fd;
2019-12-31 11:32:25 +01:00
SX_DEBUG(debug_expander, "Sending '!!' to server to request for the"
"connection to remain open\n");
if ((ret = write(fd, "!!\n", 3)) != 3) {
2021-08-17 10:25:52 +00:00
sx_report(SX_ERROR, "Partial write of multiple command mode "
"to IRRd: %i bytes, %s\n", ret, strerror(errno));
exit(1);
}
2007-03-22 18:12:32 +00:00
if (b->identify) {
2019-12-31 11:32:25 +01:00
SX_DEBUG(debug_expander, "b->identify: Sending '!n "
PACKAGE_STRING "' to server.\n");
2019-12-30 02:24:19 +00:00
char ident[128];
int ilen = snprintf(ident, sizeof(ident), "!n" PACKAGE_STRING "\n");
if (ilen > 0) {
if ((ret = write(fd, ident, ilen)) != ilen) {
2021-08-17 10:25:52 +00:00
sx_report(SX_ERROR, "Partial write of "
"identifier to IRRd: %i bytes, %s\n",
ret, strerror(errno));
exit(1);
}
memset(ident, 0, sizeof(ident));
if (0 < read(fd, ident, sizeof(ident))) {
SX_DEBUG(debug_expander, "Got answer %s", ident);
} else {
2021-08-17 10:25:52 +00:00
sx_report(SX_ERROR, "ident, failed read from IRRd\n");
exit(1);
}
} else {
sx_report(SX_ERROR, "snprintf(ident) failed\n");
exit(1);
}
}
2019-12-30 02:24:19 +00:00
/* Test whether the server has support for the A query */
if (b->generation >= T_PREFIXLIST && !STAILQ_EMPTY(&b->macroses)) {
char aret[128];
char aresp[] = "F Missing required set name for A query";
SX_DEBUG(debug_expander, "Testing support for A queries\n");
if ((ret = write(fd, "!a\n", 3)) != 3) {
2021-08-17 10:25:52 +00:00
sx_report(SX_ERROR, "Partial write of '!a' test query "
"to IRRd: %i bytes, %s\n", ret, strerror(errno));
exit(1);
}
memset(aret, 0, sizeof(aret));
if (0 < read(fd, aret, sizeof(aret))) {
if (strncmp(aret, aresp, strlen(aresp)) == 0) {
SX_DEBUG(debug_expander, "Server supports A query\n");
aquery = 1;
} else {
2021-08-17 10:25:52 +00:00
SX_DEBUG(debug_expander, "No support for A query\n");
}
} else {
2021-08-17 10:25:52 +00:00
sx_report(SX_ERROR, "A query test failed read from IRRd\n");
exit(1);
}
}
if (b->sources && b->sources[0] != 0) {
int slen = strlen(b->sources) + 4;
if (slen < 128)
slen = 128;
char sources[slen];
slen = snprintf(sources, sizeof(sources), "!s%s\n", b->sources);
if (slen > 0) {
SX_DEBUG(debug_expander, "Requesting sources %s", sources);
if ((ret = write(fd, sources, slen)) != slen) {
2021-08-17 10:25:52 +00:00
sx_report(SX_ERROR, "Partial write of sources to "
"IRRd: %i bytes, %s\n", ret, strerror(errno));
exit(1);
}
memset(sources, 0, sizeof(sources));
if (0 < read(fd, sources, sizeof(sources))) {
SX_DEBUG(debug_expander, "Got answer %s", sources);
if (sources[0] != 'C') {
2021-08-17 10:25:52 +00:00
sx_report(SX_ERROR, "Invalid source(s) "
"'%s': %s\n", b->sources, sources);
exit(1);
}
} else {
2021-08-17 10:25:52 +00:00
sx_report(SX_ERROR, "failed to read sources\n");
exit(1);
}
} else {
sx_report(SX_ERROR, "snprintf(sources) failed\n");
exit(1);
}
}
2007-03-22 18:12:32 +00:00
if (pipelining)
fcntl(fd, F_SETFL, O_NONBLOCK|(fcntl(fd, F_GETFL)));
2015-07-10 20:57:30 +03:00
STAILQ_FOREACH(mc, &b->macroses, next) {
if (!b->maxdepth && RB_EMPTY(&b->stoplist)) {
if (aquery)
bgpq_expand_irrd(b, bgpq_expanded_prefix, b,
"!a%s%s\n",
b->family == AF_INET ? "4" : "6",
mc->text);
else
bgpq_expand_irrd(b, bgpq_expanded_macro, b,
"!i%s,1\n", mc->text);
2015-07-10 16:01:22 +03:00
} else {
2021-08-17 10:06:13 +00:00
bgpq_expander_add_already(b, mc->text);
if (pipelining)
bgpq_pipeline(b, bgpq_expanded_macro_limit,
NULL, "!i%s\n", mc->text);
else
bgpq_expand_irrd(b, bgpq_expanded_macro_limit,
NULL, "!i%s\n", mc->text);
}
}
2015-07-10 16:01:22 +03:00
if (pipelining) {
if (!STAILQ_EMPTY(&b->wq))
2015-07-12 16:42:50 +03:00
bgpq_write(b);
2015-07-10 20:57:30 +03:00
if (!STAILQ_EMPTY(&b->rq))
2015-07-12 16:42:50 +03:00
bgpq_read(b);
}
2015-07-10 16:01:22 +03:00
if (b->generation >= T_PREFIXLIST || b->validate_asns) {
2018-11-30 12:40:25 +03:00
uint32_t i, j, k;
STAILQ_FOREACH(mc, &b->rsets, next) {
if (b->family == AF_INET)
bgpq_expand_irrd(b, bgpq_expanded_prefix,
NULL, "!i%s,1\n", mc->text);
else
bgpq_expand_irrd(b, bgpq_expanded_v6prefix,
NULL, "!i%s,1\n", mc->text);
}
for (k=0; k < sizeof(b->asn32s) / sizeof(unsigned char*); k++) {
if (!b->asn32s[k])
continue;
for (i=0; i<8192; i++) {
for (j=0; j<8; j++) {
if (b->asn32s[k][i] & (0x80 >> j)) {
if (b->family == AF_INET6) {
if (!pipelining) {
2018-11-30 12:40:25 +03:00
bgpq_expand_irrd(b, bgpq_expanded_v6prefix,
NULL, "!6as%" PRIu32 "\n", ( k << 16) + i * 8 + j);
} else {
2018-11-30 12:40:25 +03:00
bgpq_pipeline(b, bgpq_expanded_v6prefix,
NULL, "!6as%" PRIu32 "\n", (k << 16) + i * 8 + j);
}
} else {
if (!pipelining) {
2018-11-30 12:40:25 +03:00
bgpq_expand_irrd(b, bgpq_expanded_prefix,
NULL, "!gas%" PRIu32 "\n", (k << 16) + i * 8 + j);
} else {
2018-11-30 12:40:25 +03:00
bgpq_pipeline(b, bgpq_expanded_prefix,
NULL, "!gas%" PRIu32 "\n", ( k<< 16) + i* 8 + j);
}
}
}
}
}
}
if (pipelining) {
if (!STAILQ_EMPTY(&b->wq))
2015-07-12 16:42:50 +03:00
bgpq_write(b);
2015-07-10 20:57:30 +03:00
if (!STAILQ_EMPTY(&b->rq))
2015-07-12 16:42:50 +03:00
bgpq_read(b);
}
}
2015-06-23 14:56:05 +03:00
if ((ret = write(fd, "!q\n", 3)) != 3) {
sx_report(SX_ERROR, "Partial write of quit to IRRd: %i bytes, %s\n",
ret, strerror(errno));
// not worth exiting due to this
}
2019-08-15 20:11:03 +03:00
if (pipelining) {
int fl = fcntl(fd, F_GETFL);
fl &= ~O_NONBLOCK;
fcntl(fd, F_SETFL, fl);
}
2015-07-10 20:57:30 +03:00
close(fd);
2007-03-22 18:12:32 +00:00
return 1;
}
2007-03-22 18:12:32 +00:00