Ключевые слова:ssh, flood, security, (найти похожие документы)
_ RU.LINUX (2:5077/15.22) ___________________________________________ RU.LINUX _
From : Solar Designer 2:5020/400 27 Nov 98 00:59:24
Subj : Hедостатки ssh
________________________________________________________________________________
From: Solar Designer <[email protected]>
Solar Designer <[email protected]> wrote:
> Именно поэтому я и говорю, что задача нетривиальная. Также, поэтому я
> говорю насчет поддержки в ядре (SYN flood'ы -- это его дело). Короче,
> тут просто надо начать пробовать, я лучше не буду много рассуждать.
Вот и попробовал. Все получается как надо. Единственный недостаток --
не удается послать RST сразу -- 3-way handshake происходит вообще до
accept(2). Впрочем, никаких опасных последствий от этого не вижу.
А так, на 2.0.36 с SYN cookies, даже при DAEMON_SYN_LIMIT=1 (см. пример
ниже) все живет без проблем. Проверялось под одновременным SYN и connect()
флудом, и нормально пропускало и обрабатывало соединение с другого адреса.
Можно будет в таком стиле (только аккуратнее, чем в примере) делать и для
SSH и для xinetd.
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define DAEMON_PORT 9999
#define DAEMON_SYN_LIMIT 1
#define DAEMON_SOURCE_LIMIT 2
#define DAEMON_TOTAL_LIMIT 3
struct source {
struct in_addr addr;
int pid;
};
int total;
struct source source[DAEMON_TOTAL_LIMIT];
int ptr, found;
void pexit(char *s)
{
perror(s);
exit(1);
}
void handle_connection(int sock)
{
char c;
if (read(sock, &c, 1) == 1)
write(sock, &c, 1);
}
void handle_child()
{
int status, pid;
int i;
if ((pid = wait(&status)) > 0) {
total--;
for (i = 0; i < DAEMON_TOTAL_LIMIT; i++)
if (source[i].pid == pid) {
source[i].addr.s_addr = 0;
source[i].pid = 0;
break;
}
if (i == DAEMON_TOTAL_LIMIT) found = 0;
}
signal(SIGCHLD, handle_child);
}
int main()
{
int sock, new;
int true = 1;
struct sockaddr_in addr;
int addrlen;
int i, n;
if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
pexit("socket");
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &true, sizeof(true)))
pexit("setsockopt");
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(DAEMON_PORT);
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)))
pexit("bind");
if (listen(sock, DAEMON_SYN_LIMIT))
pexit("listen");
signal(SIGCHLD, handle_child);
total = 0;
memset(source, 0, sizeof(source));
while (1) {
addrlen = sizeof(addr);
new = accept(sock, (struct sockaddr *)&addr, &addrlen);
if (new < 0) {
if (errno != EINTR) perror("accept");
continue;
}
printf("Connection from %s\n", inet_ntoa(addr.sin_addr));
if (total >= DAEMON_TOTAL_LIMIT)
goto reject;
n = 0;
for (i = 0; i < DAEMON_TOTAL_LIMIT; i++)
if (source[i].addr.s_addr == addr.sin_addr.s_addr) n++;
if (n >= DAEMON_SOURCE_LIMIT)
goto reject;
ptr = 0;
while (source[ptr].pid && ptr < DAEMON_TOTAL_LIMIT - 1) ptr++;
found = 1;
switch ((source[ptr].pid = fork())) {
case -1:
perror("fork");
break;
case 0:
handle_connection(new);
exit(0);
default:
total++;
source[ptr].addr = addr.sin_addr;
if (!found) {
source[ptr].addr.s_addr = 0;
source[ptr].pid = 0;
}
}
reject:
if (close(new))
pexit("close");
}
return 0;
}
--
/sd
--- ifmail v.2.14dev2 * Origin: DataForce ISP (2:5020/400@fidonet)