Вероятно, наиболее универсальным и индивидуальным подходом к завершению вашего квеста является 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