axfrdns (net-dns/djbdns) – нехватка памяти

Для начала, мне не совсем понятно, кому отправлять issues и patches в отношении djbdns (автор очень давно все допилил до стабильности и отдал в public domain; в генте как видимо в других дистро, только патчсеты). К патчсетам проблема отношения не имеет плюс я до конца так и не смог в ней разобраться, а смог только весьма тупо ее пофиксить. А хотелось бы конечно сделать все грамотно. Но собственно сама проблема:

1. axfrdns отвечает на AXFR запросы и отдает запрошенную зону, используя ту же бинарную БД (data.cdb) что и tinydns (который собственно DNS сервер и отвечает на все остальные запросы). в моей зоне уже много лет 2-4 десятка записей, некоторые (А) из них время от времени меняются, но в целом все без изменений.
2. несколько дней назад я заметил, что secondary сервера не могут обновить зону, в логах axfrdns – axfrdns: fatal: unable to read data.cdb: format error. Провозившись некоторое время, я заметил, что если в зоне будет всего 5-7 записей, то она отдается без ошибок.
3. исследование проблемы показало, что при очередном запросе на выделение (19!) байтов фейлится вызов char *alloc(n) из alloc.c:

#include 
#include "alloc.h"
#include "error.h"

#define ALIGNMENT 16 /* XXX: assuming that this alignment is enough */
#define SPACE 2048 /* must be multiple of ALIGNMENT */

typedef union { char irrelevant[ALIGNMENT]; double d; } aligned;
static aligned realspace[SPACE / ALIGNMENT];
#define space ((char *) realspace)
static unsigned int avail = SPACE; /* multiple of ALIGNMENT; 0<=avail<=SPACE */

/*@null@*//*@out@*/char *alloc(n)
unsigned int n;
{
  char *x;
  n = ALIGNMENT + n - (n & (ALIGNMENT - 1)); /* XXX: could overflow */
  if (n <= avail) { avail -= n; return space + avail; }
  x = malloc(n);
  if (!x) errno = error_nomem;
  return x;
}

void alloc_free(x)
char *x;
{
  if (x >= space)
    if (x < space + SPACE)
      return; /* XXX: assuming that pointers are flat */
  free(x);
}

Изменив #define SPACE на 8192, проблема была решена. Хотя я не погромист на С, но мне тут более-менее понятно, что автор сначала выделяет память из realspace[SPACE / ALIGNMENT], а потом уже malloc. Видимо это такая мегаоптимизация, но суть не в этом. Понятно, что исходные 2048 байтов быстро исчерпываются, но почему с выделением памяти вообще начала появляться проблема? Интересно и то, что tinydns никакой проблемы не испытывает.

Проблема как будто бы появилась практически на пустом месте. Ничего нигде не менялось, разве что примерно в окрестностях даты ее возникновения был собран gcc 7 (c пересборкой тулчейна и глибца), но как это вообще может относиться к проблеме – совершенно не ясно. Пакет изначально был собран хз когда (не 7м gcc), но его пересборка ничего не изменила. Какие будут мысли и соображения?

А железо не менялось?

А железо не менялось?

Еще можно предположить, что это как-то связано с размером блока в БД и/или ФС (выравнивание и т.п.).

Ничего не менялось (кроме как

Ничего не менялось (кроме как я говорил, гцц), просто внезапно сломалось. Аптайм 55 дней. там собственно «БД» судя по коду – минималистичнейшая, не более чем упаковка строк с минимальной структурой. (да в пакете то и зависимостей никаких нет, поэтому я про глибц и подумал). Не и никаких полей-хэшей-индексов итд. Реализовано чтение зоны из этой «БД» тоже суперминималистично.

… в смысле каких-то блоков в

… в смысле каких-то блоков в этом смысле там похоже просто нет, а весь io «БД» ограничивается вызовом open_read():

int open_read(const char *fn)                                                                                                                                                                                                                                
{ return open(fn,O_RDONLY | O_NDELAY); }    

Это только открытие.

Это только открытие. Но ведь потом это читается как-то... возможно в новой библиотеке (а там много чего поменяли!) другие дефолтовые параметры и пр.

Меня смущает, что вылет происходит именно на операции чтения...

«читается» там из mmap: void

«читается» там из mmap:

void cdb_init(struct cdb *c,int fd)
{
  struct stat st;
  char *x;

  cdb_free(c);
  cdb_findstart(c);
  c->fd = fd;

  if (fstat(fd,&st) == 0)
    if (st.st_size <= 0xffffffff) {
      x = mmap(0,st.st_size,PROT_READ,MAP_SHARED,fd,0);
      if (x + 1) {
    c->size = st.st_size;
    c->map = x;
      }
    }
}

Да и читается все без проблем, ошибка возникает при распаковке (я так понял что это распаковка) упакованного «поля» в момент попытки выделения памяти для распаковываемой строки. В общем в районе ошибки ничего внешнего кроме malloc точно не вызывается

Собственно я понимаю что

Собственно я понимаю что здесь классическое спасение утопающего.
Однако если кто-то смог бы вкратце пояснить как это пересобрать так чтобы пошагово отладить (тут никаких потоков нет, так что все просто должно быть) и собственно отладить, то, думаю, я бы справился с проблемой.

проблема еще и в том, что запускается это так:

tcpserver -vDRHl0 -x tcp.cdb -- $IP $PORT /usr/bin/axfrdns

вроде бы запрос пишется в stdin/usr/bin/axfrdns, читается из stdout, но получается совсем не то если без tcpserver запускать.

ничего не могу посоветовать на эту тему

Я уже более четверти века не занимаюсь разработкой и изрядно все подзабыл, поэтому ничего не могу посоветовать на эту тему. Но могу дать "админский" совет - забей и поставь любой нормальный ДНС сервер по своему вкусу (BIND, PowerDNS и т.п.). Сэкономишь себе кучу времени и нервов. Если, разумеется, копание в этих кодах не самоцель и самоутверждение... ;)

djbdns, как и qmail, конечно, круто, я сам с ними лет 20 назад долго игрался в серьезной конторе с серьезным подходом к безопасности (на уровне PCI DSS), но, к сожалению, этими системами никто уже давно реально не занимается и они потихоньку умирают... Если же ты держишься за эту штуку из-за параноидального подхода к безопасности - так в системе есть и другие потенциальные дыры! :) Что толку, если тебя сломают не через ДНС, а через какой-нибудь другой сервис?.. Если там вообще есть ради чего стараться... А ресурсы для того же BIND'а на твою задачу совсем не проблема. Даже на старом железе и/или виртуалке.

И ты верно подметил, что автору было важно продемонстрировать работающую модель по его идеям (теории), а поддержка и развитие ему неинтересны... так что вот...

P.S. Не в тему, но интересно: почему этот топик не форматируется в окне, а разъезжается в ширину? Да так, что приходится пользоваться скроллингом... И колонка слева ужата донельзя... А вот с другими топиками все нормально... и тут, если нажмешь ответить форматирование нормальное.

тут вопрос скорее в затратах

тут вопрос скорее в затратах на переход. в djbdns все очень и очень замечательно просто, включая синтаксис определения зоны и скриптинг внесения изменений в нее. имеется 3 или 4 задачи, которые вносят в нее изменения, нечастые, но тем не менее. да и работало все это уже хз сколько – тоже просто и надежно как grep. c биндом (включая тот факт, что у меня только 2 зоны – прямая/обратная но есть и записи вида A.subdomain.domain.tld) и учитывая совершенно другой синтаксис, я не смогу просто взять-и-пересесть на него, кроме того плюс не поимев неочевидных проблем впоследствии.

ну и ясно мне что проблема, описанная в этом топике, по сути очень простая… было бы просто обидно и стыдно ее не решить; некоторый затык в отсутствии необходимых навыков и желании сэкономить на их наработке.

автору скорее просто давно уже нечего делать с этим проектом (идея полностью реализована), да и DNS весьма консервативная система; полагаю, что в таких простых применениях как моё, djbdns и было и есть – наилучший выбор. когда я давным-давно читал доки и по bind и по djbdns – заметил, что с точки зрения последнего все выглядит гораздо проще. ну и как ты подметил, сломать такое в принципе гораздо сложнее – все дырки уже заделаны, код стабилен и прост как хелловорлд, имея мало потенциальных уязвимостей. патчи безопасности – их есть в ебилде.

разъезжается, да. может все же ты поднимешь свой голос за то, что музейный форум давно просит замены? ;-) вот без всяких подколов скажу – это самый убогий говнофорум (в техническом отношении), на котором я регулярно бываю. your bunny steed а не форум.

Думаю что вполне GCC 7 мог

Думаю что вполне GCC 7 мог вполне что-то там наоптимизиовать до полной поломки, хотя сломалось оно и до него...
Учитывая общее состояние djbdns - можно поискать патчи в интернетах/дистрибутивах, или по крайней мере попробовать поиграться с их количеством.

интернеты увы молчат про

интернеты увы молчат про данныю проблему; вполне возможно, что все пострадавшие либо решили ее костылем (как я) либо просто пока не озаботились опубликовать решение.
проблема тут 100% в выделении памяти в alloc.c и она явно очень простая. вполне возможно, опытный погромист увидит проблему прямо в коде, но мне необходима пошаговая отладка и видеть что происходит в счетчиках и буферах. единственное что сильно глубоко в это погружаться не особо есть время. было бы идеально поглядеть в какой-нить понятный и наглядный мануал по теме.

/

Ты Брукса достаточно хорошо помнишь?

Согласно моим представлениям о правильности, независимо от оценки благодарности, стоит озвучить проблему в родном трекере.
Там по крайней мере должны быть дэвы, представляющие себе логику и направление эволюции компилляторов с окружением.

:wq
--
Live free or die

Занятно, что спустя столько

Занятно, что спустя столько лет я тоже на это наткнулся. И "вылечил" несколько другим подходом: увеличением softlimit с -d300000 на -d3000000 в скрипте запуска axfrdns /service/axfrdns/run

Настройки просмотра комментариев

Выберите нужный метод показа комментариев и нажмите "Сохранить установки".