Linux обеспечивает два механизма для того, чтобы следить за развитием событий файловой системы; dnotify
и inotify
.
Более старые из этих двух, dnotify
, был представлен в версии 2.4.0 ядра. Это позволяет приложениям регистрироваться для получения уведомлений на изменениях в каталоге через fcntl()
интерфейс. Сами уведомления поставляются через сигналы. dnotify
механизм ограничен наблюдением изменений в каталоге, это не позволяет контролировать отдельных файлов. Кроме того, это требует поддержания открытого дескриптора файла к контролируемому каталогу. dnotify
механизм удерживался от использования в 2.6.13, когда inotify
был представлен.
Новые программы должны использовать inotify
механизм, который поддерживает контроль обоих каталогов и отдельных файлов. Это, однако, не на основе сигналов. inotify
экземпляр связан с дескриптором файла. Уведомления о событии могут быть прочитаны из этого дескриптора файла.
Ограничение обоих механизмов - то, что нет никакой опции смотреть каталоги рекурсивно. Это означает, что контроль должен быть установлен отдельно для каждого каталога в поддереве, за которым нужно наблюдать.
Пример (dnotify
):
#define _GNU_SOURCE
#include
#include
#include
#include
/* For error handling */
#include
#include
#include
static volatile int event_fd;
static void handler(int sig, siginfo_t *si, void *data)
{
event_fd = si->si_fd;
}
int main(int argc, char *argv[])
{
struct sigaction sa;
int fd;
if(argc < 2)
error(EXIT_FAILURE, 0, "missing argument");
sa.sa_sigaction = handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_SIGINFO;
sigaction(SIGRTMIN + 1, &sa, NULL);
if((fd = open(argv[1], O_RDONLY)) < 0)
error(EXIT_FAILURE, errno, "failed to open '%s'", argv[1]);
if(fcntl(fd, F_SETSIG, SIGRTMIN + 1) < 0)
error(EXIT_FAILURE, errno, "failed to set dnotify signal");
if(fcntl(fd, F_NOTIFY, DN_MODIFY|DN_CREATE|DN_DELETE|DN_MULTISHOT))
error(EXIT_FAILURE, errno,
"failed to register notification for '%s'", argv[1]);
while (1) {
pause();
printf("event occured for fd=%d\n", event_fd);
}
}
Объяснение:
fcntl(fd, F_SETSIG, SIGRTMIN + 1)
Устанавливает сигнал, отправленный, когда события уведомления имеют место. Значение нуля указывает на это SIGIO
(значение по умолчанию), отправляется. Любое другое значение, включая SIGIO
, интерпретируется как сигнал, который будет отправлен вместо этого. В последнем случае обработчик сигналов получает a siginfo_t
структура как ее второй аргумент, и si_fd
поле структуры будет содержать дескриптор файла, который генерировал событие.
Если сигнал в реальном времени (>= SIGRTMIN
) используется для уведомлений, несколько событий I/O могут быть поставлены в очередь с помощью того же числа сигнала (в зависимости от доступной памяти). Сигнал в реальном времени должен использоваться особенно при использовании DN_MULTISHOT
.
fcntl(fd, F_NOTIFY, DN_MODIFY|DN_CREATE|DN_DELETE|DN_MULTISHOT)
Устанавливает события, которые вызовут уведомления, когда каталог, упомянутый fd или любыми файлами, которые он содержит, будет изменен. Доступные типы событий:
DN_ACCESS
К файлу получают доступ.DN_MODIFY
Файл изменяется.DN_CREATE
Файл создается.DN_DELETE
Файл является несвязанным.DN_RENAME
Файл переименован в рамках каталога.DN_ATTRIB
Атрибуты файла изменяются.Уведомления обычно одноразовы, т.е. приложение должно повторно зарегистрироваться для получения дальнейших уведомлений. Если DN_MULTISHOT
указан, уведомления останутся в силе, пока явно не удалено.
Пример (inotify
):
#include
#include
#include
/* For PATH_MAX */
#include
/* For error handling */
#include
#include
int main(int argc, char *argv[]) {
int fd, wd, len, i;
char buf[sizeof(struct inotify_event) + PATH_MAX];
if (argc < 2)
error(EXIT_FAILURE, 0, "missing argument");
if ((fd = inotify_init()) < 0)
error(EXIT_FAILURE, errno, "failed to initialize inotify instance");
for (i = 1; i < argc; i++) {
if ((wd = inotify_add_watch (fd, argv[i],
IN_MODIFY | IN_CREATE | IN_DELETE)) < 0)
error(EXIT_FAILURE, errno,
"failed to add inotify watch for '%s'", argv[i]);
}
while ((len = read(fd, buf, sizeof(buf))) > 0) {
i = 0;
while (i < len) {
struct inotify_event *ie = (struct inotify_event*) &buf[i];
printf("event occured for '%s': ", argv[ie->wd]);
if (ie->mask & IN_MODIFY)
printf("%s was modified\n", ie->len ? ie->name : "file");
else if (ie->mask & IN_CREATE)
printf("%s was created\n", ie->name);
else if (ie->mask & IN_DELETE)
printf("%s was deleted\n", ie->name);
else
printf("unexpected event\n");
i += sizeof(struct inotify_event) + ie->len;
}
}
error(EXIT_FAILURE, len == 0 ? 0 : errno, "failed to read inotify event");
}
Объяснение:
fd = inotify_init()
Инициализирует новое inotify
экземпляр. Возвращаемое значение является дескриптором файла, связанным с недавно созданный inotify
очередь событий. По умолчанию дескриптор файла блокируется.
wd = inotify_add_watch (fd, argv[i], IN_MODIFY | IN_CREATE | IN_DELETE)
Новые объекты к списку часов, иначе часы добавляются с inotify_add_watch()
. Третьим аргументом является битовая маска, используемая для указания inotify
события для наблюдения за. Доступные типы событий:
IN_ACCESS
К файлу получают доступ.IN_ATTRIB
Атрибуты файла изменяются.IN_CLOSE_WRITE
Файл, открытый для записи, закрывается.IN_CLOSE_NOWRITE
Файл, открытый только для чтения, закрывается.IN_CREATE
Файл или каталог создается в рамках наблюдаемого каталога.IN_DELETE
Файл или каталог удален в рамках наблюдаемого каталога.IN_DELETE_SELF
Наблюдаемый файл или каталог удален.IN_MODIFY
Файл был изменен.IN_MOVE_SELF
Наблюдаемый файл или каталог перемещен.IN_MOVED_FROM
Файл перемещен из наблюдаемого каталога.IN_MOVED_TO
Файл перемещен в наблюдаемый каталог.IN_OPEN
Файл открыт.IN_ALL_EVENT
Все вышеупомянутое.IN_MOVE
Эквивалентный IN_MOVED_TO|IN_MOVED_FROM
IN_CLOSE
Эквивалентный IN_CLOSE_WRITE|IN_CLOSE_NOWRITE
Следующие опции могут также быть установлены в аргументе маски inotify_add_watch()
:
IN_DONT_FOLLOW
Не следуйте за символьными ссылками.IN_EXCL_UNLINK
Не генерируйте события для несвязанных файлов, которые раньше были в наблюдаемом каталоге.IN_MASK_ADD
Добавьте наблюдаемые события кумулятивно, если часы уже существуют.IN_ONESHOT
Автоматически удалите часы после одного события от него.IN_ONLYDIR
Только наблюдайте путь, если это - каталог.Значение, возвращенное inotify_add_watch()
дескриптор часов, связанный с объектом файловой системы, наблюдаемым в inotify
экземпляр, обозначенный fd
. Если за указанным объектом уже наблюдают, дескриптор для существующих часов возвращается.
while ((len = read(fd, buf, sizeof(buf))) > 0) {
i = 0;
while (i < len) {
struct inotify_event *ie = (struct inotify_event*) &buf[i];
/* ... */
i += sizeof(struct inotify_event) + ie->len;
}
}
Каждый успешный read()
от дескриптора файла, связанного с inotify
экземпляр возвращает один или несколько inotify_event
структуры со следующими полями.
int wd
Наблюдайте дескриптор инициированных часов.uint32_t mask
Маска событий, которые инициировали часы.uint32_t cookie
Уникальный cookie, связывающий связанные события.uint32_t len
Размер поля имени.char name[]
Дополнительное завершенное пустым указателем название файла, который инициировал событие в наблюдаемом каталоге.В дополнение к битам, соответствующим типам событий, передал inotify_add_watch()
, полю маски можно было установить следующие биты состояния:
IN_IGNORED
Часы были удалены (через inotify_rm_watch()
, путь, несвязанный и т.д.).IN_ISDIR
Событие инициировано каталогом.IN_Q_OVERFLOW
Очередь событий переполнена. Кроме того, wd установлен на-1.IN_UNMOUNT
Файловая система, содержащая наблюдаемый путь, была размонтирована.Длина каждого inotify_event
структура sizeof(inotify_event) + len
из-за переменной длины name
поле.
До версии 2.6.21 ядра, если буфер передал read()
является слишком маленьким, чтобы провести следующее мероприятие, читать (), возвратился бы 0. С тех пор 2.6.21, read()
сбои и errno
установлен на EINVAL
.
Любой другой брандмауэр будет иметь ту же проблему, что и PF, поскольку все они должны сохранить некоторое тип «состояния», чтобы позволить пакетам вернуться к устройству за Nat или другим видом Входящий блок, который позволяет ответить, но останавливает новые пакеты.
Случай 1: клиент UDP внутри брандмауэра инициирует обмен данными с сервером UDP. Брандмауэр создает запись сопоставления, чтобы разрешить продолжение разговора. Злоумышленник использует это для подмены некоторых пакетов в обратном направлении.
Во-первых, пакеты необходимо подделать, чтобы они выглядели так, как будто они исходят от сервера, иначе они не будут совпадать на удаленном адресе. Они также должны быть направлены на IP-адрес и UDP-порт клиента, иначе они не пройдут через брандмауэр. Таким образом, эти поддельные пакеты достигают клиента, который думает, что они исходят от сервера: они принимаются клиентским приложением, даже если его сокет дейтаграммы помечен как подключенный к серверу. Если приложение написано надежно, они в конечном итоге отбрасываются на уровне внутреннего протокола, потому что не проходят проверки целостности (шифрование и контрольные суммы). Поддельные дейтаграммы UDP, конечно же, нанесут ущерб изначально небезопасным приложениям; это не вина брандмауэра.
Случай 2: UDP-сервер внутри брандмауэра имеет постоянный переадресацию порта. Конечно, любой может отправить туда UDP; ему просто нужно проверять пакеты и поддерживать только безопасные сеансы с аутентификацией.
No es un riesgo significativo en el escenario que describe.
Un atacante capaz de espiar el tráfico UDP ya se encuentra en una posición muy privilegiada. En realidad, no es particularmente relevante que una conexión esté o no listada en una tabla de seguimiento de conexiones.
Desde la perspectiva de la red, un atacante normalmente querrá a )observar el tráfico y los datos que van y vienen del host yb )modificar algunos de ellos para adaptarlos a un propósito particular. Luego, según el objetivo, la información podría usarse para hacerse pasar por el host o una entidad, intentar comprometer el host, atacar a otros hosts, etc.