2

У меня есть небольшой BASH-скрипт, который я хотел бы запустить на нескольких Mac (смесь 10.8.5 и 10.9.4). Я хотел бы запустить скрипт всякий раз, когда мой Mac пытается подключиться к другому через определенный порт TCP. IP-адреса обоих компьютеров известны, и я вижу трафик (соединение через порт 6472), когда смотрю через неттоп или консоль.

То, что я не смог найти - и, возможно, я не ищу правильно - это инструмент, который будет работать в фоновом режиме и отслеживать этот запрос на подключение, а затем запускать исполняемый файл, когда это происходит. Я полагаю, я мог бы приготовить один, но это похоже на проблему, которую уже решили другие. Любое направление к существующему решению будет приветствоваться.

Спасибо! Майк

3 ответа3

0

Вероятно, наиболее универсальным и индивидуальным подходом к завершению вашего квеста является dtrace .

Либо используйте общий сокет или tcp провайдера и запустите скрипт в деструктивном режиме для вызова system() из ядра, либо используйте функцию Boundary Tracing (FBT) в качестве вашего провайдера. Последнее сделает ваш скрипт зависимым от версии OSX.

Немного поиграв, я придумал что-то, что должно дать вам достаточно фуража для вашего окончательного решения с использованием провайдера сокетов (так что оно должно работать на обеих ваших машинах MacOSX):

#!/usr/sbin/dtrace -s

#pragma D option quiet
#pragma D option switchrate=10hz
#pragma D option destructive 

/* AF_INET{6} are unknown to dtrace, so replace with numbers */
inline int af_inet  =  2; /* AF_INET  */
inline int af_inet6 = 30; /* AF_INET6 */
inline const string procname = "nc";

dtrace:::BEGIN
{
    /* Add translations as desired from /usr/include/sys/errno.h */
    err[0]            = "Success";
    err[EINTR]        = "Interrupted syscall";
    err[EIO]          = "I/O error";
    err[EACCES]       = "Permission denied";
    err[ENETDOWN]     = "Network is down";
    err[ENETUNREACH]  = "Network unreachable";
    err[ECONNRESET]   = "Connection reset";
    err[ECONNREFUSED] = "Connection refused";
    err[ETIMEDOUT]    = "Timed out";
    err[EHOSTDOWN]    = "Host down";
    err[EHOSTUNREACH] = "No route to host";
    err[EINPROGRESS]  = "In progress";
    err[EADDRNOTAVAIL] = "Can't assign requested address";

    printf("%-6s %-20s %-8s %-21s %-21s %-8s %s\n", 
        "PID", "PROCNAME", "FAMILY", "S_ADDR:S_PORT", "D_ADDR:D_PORT", 
        "LAT(us)", "RESULT");
}

/*  MacOSX connectx() syscall:

    connectx(arg0:int s, arg1:struct sockaddr *src, arg2:socklen_t srclen, 
                         arg3:struct sockaddr *dsts, arg4:socklen_t dstlen, 
                         arg5:uint32_t ifscope, arg6: associd_t aid, 
                         arg7:connid_t *cid);
*/

syscall::connectx:entry
{
    this->s = (struct sockaddr_in *) copyin(arg3, sizeof(struct sockaddr)); 
    this->f = this->s->sin_family;
} 

syscall::connectx:entry 
/ this->f == af_inet && execname == procname / 
{ 
    this->s = (struct sockaddr_in *) copyin(arg1, sizeof(struct sockaddr)); 
    self->address = inet_ntop(this->f, (void *) &this->s->sin_addr);
    self->port = ntohs(this->s->sin_port);
    self->s_addr = strjoin(strjoin(self->address, ":"), lltostr(self->port));

    this->d = (struct sockaddr_in *) copyin(arg3, sizeof(struct sockaddr)); 
    self->address = inet_ntop(this->f, (void *) &this->d->sin_addr);
    self->port = ntohs(this->d->sin_port);  
    self->d_addr = strjoin(strjoin(self->address, ":"), lltostr(self->port));

    self->ts = timestamp; 
}

syscall::connectx:entry
/ this->f == af_inet6 && execname == procname /
{
    this->s6 = (struct sockaddr_in6 *) copyin(arg1, sizeof(struct sockaddr_in6));
    self->port = ntohs(this->s6->sin6_port);
    self->address = inet_ntop(this->f, (void *) &this->s6->sin6_addr);
    self->s_addr = strjoin(strjoin(self->address, ":"), lltostr(self->port));

    this->d6 = (struct sockaddr_in6 *) copyin(arg3, sizeof(struct sockaddr_in6));
    self->port = ntohs(this->d6->sin6_port);
    self->address = inet_ntop(this->f, (void *) &this->d6->sin6_addr);
    self->d_addr = strjoin(strjoin(self->address, ":"), lltostr(self->port));

    self->ts = timestamp;
}

syscall::connectx:return 
/ self->ts / 
{ 
    this->delta = (timestamp - self->ts) / 1000; 
    this->errstr = err[errno] != NULL ? err[errno] : lltostr(errno);

    /* Basically anything can be called here */
    system("date");
    printf("%-6d %-20s %-8d %-21s %-21s %-8d %s\n", 
        pid, execname, this->f, self->s_addr, self->d_addr,
        this->delta, this->errstr); 

    self->family = 0; 
    self->ts = 0; 
}

Сохраните его в файл (скажем, ./socket_connect_mac_simple.d), а затем вызовите код следующим образом:

$ sudo ./socket_connect_mac_simple.d

Откройте другой терминал и запустите nc как сервер:

$ nc -4 -k -l 127.0.0.1 6472 > /dev/null

И в еще одном терминале подключитесь к нему:

$ while :; do nc -4 -s 192.168.0.19 127.0.0.1 6472 < /usr/bin/true; sleep 0.5; done

Ваш вывод должен выглядеть примерно так:

$ sudo ./socket_connect_mac_simple.d
PID    PROCNAME         FAMILY   S_ADDR:S_PORT         D_ADDR:D_PORT         LAT(us)  RESULT
45823  nc               2        192.168.0.19:0        127.0.0.1:6472        240      Success
45825  nc               2        192.168.0.19:0        127.0.0.1:6472        234      Success
45827  nc               2        192.168.0.19:0        127.0.0.1:6472        236      Success
45829  nc               2        192.168.0.19:0        127.0.0.1:6472        240      Success
45831  nc               2        192.168.0.19:0        127.0.0.1:6472        241      Success
45833  nc               2        192.168.0.19:0        127.0.0.1:6472        238      Success
45835  nc               2        192.168.0.19:0        127.0.0.1:6472        234      Success
45837  nc               2        192.168.0.19:0        127.0.0.1:6472        241      Success
45839  nc               2        192.168.0.19:0        127.0.0.1:6472        236      Success
45841  nc               2        192.168.0.19:0        127.0.0.1:6472        237      Success

Очевидно, вы замените nc списком демонов на порту 6472, и вам также придется вызвать ваш скрипт bash, где я поместил фрагмент кода system("date") . Кроме этого, он должен просто работать так, как вы его описали.

Убедитесь, что вы прочитали хорошую документацию о деструктивном режиме dtrace call system(): вызовы деструктивного режима внутри DTrace

0

Как насчет запуска чего-то подобного в фоновом режиме, использования tcpdump с правильным фильтром и запуска вашего скрипта каждый раз, когда он совпадает?

tcpdump -l -i eth0 'dst host other_host and dst port 6472 and tcp[tcpflags] = tcp-syn' 2>/dev/null | while read f ; do your_script; done

замените eth0 вашим сетевым интерфейсом, other_host - IP-адресом другой машины

Если вы не хотите, чтобы окно терминала лежало вокруг, вы можете сделать это bash-скриптом и запустить его в сеансе экрана .

0

Другой альтернативой и, возможно, более простым решением для @ultrasawblade может быть запуск knockd. - Похоже, есть версия, доступная для Mac.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .