Como executar um script BASH em resposta a um evento de rede?

2

Eu tenho um pequeno script BASH que gostaria de rodar em alguns Macs (uma mistura de 10.8.5 e 10.9.4). Gostaria de acionar o script sempre que meu mac tentar se conectar a outro através de uma porta TCP específica. Os endereços IP de ambos os computadores são conhecidos e posso ver o tráfego (conexão na porta 6472) quando assisto via nettop ou console.

O que não consegui encontrar - e talvez não esteja pesquisando corretamente - é uma ferramenta que será executada em segundo plano e observará a solicitação de conexão, depois executará um executável quando ocorrer. Suponho que poderia preparar um, mas isso parece ser um problema que outros já resolveram. Qualquer direção para uma solução existente seria bem-vinda.

Obrigado! Mike

Mike
fonte

Respostas:

0

Que tal executar algo parecido com isso em segundo plano, usando tcpdump com o filtro certo e ativando seu script sempre que ele corresponder?

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

substitua eth0pela sua interface de rede other_hostpelo endereço IP da outra máquina

Se você não deseja uma janela de terminal, pode fazer deste um script bash e executá-lo dentro de uma sessão de tela .

limões
fonte
0

Outra alternativa e, possivelmente, a solução mais simples da solução @ultrasawblade pode ser executar o knockd . - Parece que há uma versão disponível para Mac.

davidgo
fonte
Obrigado, parece que ele fará exatamente o que eu preciso com um mínimo de barulho. Faltam alguns dias para que eu possa experimentar, mas agradeço a sugestão!
Mike
0

Provavelmente, a abordagem mais versátil e personalizada para concluir sua busca é ler atentamente dtrace.

Use um soquete genérico ou provedor tcp e execute o script no modo destrutivo para chamar system()do kernel ou use Rastreamento de Limite de Função (FBT) como seu provedor. Este último tornará seu script dependente da versão do OSX.

Brincando um pouco, eu vim com algo que deveria lhe fornecer forragem suficiente para a sua solução final usando um provedor de soquete (para que ele funcione nas duas máquinas 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; 
}

Salve-o em um arquivo (digamos ./socket_connect_mac_simple.d) e, em seguida, chame o código da seguinte maneira:

$ sudo ./socket_connect_mac_simple.d

Abra outro terminal e inicie nccomo servidor:

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

E em outro terminal, conecte-se a ele:

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

Sua saída deve parecer algo assim:

$ 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

Obviamente, você estará substituindo ncsua lista de daemon na porta 6472 e também precisará chamar seu script bash onde coloquei o system("date")fragmento de código. Fora isso, deve funcionar exatamente como você o descreveu.

Certifique-se de ler a documentação detalhada sobre a chamada do modo destrutivo do dtrace system(): Chamadas do modo destrutivo no DTrace

Moreaki
fonte