Вы немного запутались в том, какие IP-адреса использовать. При переадресации портов есть две пары IP/портов:
<from IP>:<from PORT>:<to IP>:<to PORT>
Если вы устанавливаете только один IP-адрес, это читается как
<from PORT>:<to IP>:<to PORT>
Это сбивает с толку, потому что «от ip от порта» к клиенту ssh и «от ip к порту» исходят от сервера.
Попробуйте это с сервера А:
ssh -N -f -L 2222:localhost:22 admin@10.10.10.1
Затем вы можете
ssh 43.24.24.29:2222
Это работает, потому что SSH-соединение осуществляется от сервера A к серверу B. Таким образом, в приведенной выше команде «localhost» относится к серверу B.
Пока не будет доступно что-то более подходящее, вот ответ, который пытается абсолютно не -промышленным способом найти процессы, которые использовали bind(2)
на сокете TCP, но затем не сделали ни listen(2)
, ни connect(2)
, а также может отображать привязанный TCP-адрес.
Требуется getfattr
, найденный в пакете с именем attr
в большинстве дистрибутивов, плюс ядро >= 3.7 для фильтрации сокетов TCP, отличных от -, и минимальная установка gdb
(, например, в Debian:gdb-minimal
). Не требует среды разработки. Следует запускать от имени пользователя root (, иначе будет найдена информация только об одних и тех же пользователях, но это даже не будет работать в контейнерах ). См. Предостережения в конце.
Компоненты:
Первый сценарий оболочки имитирует часть того, что должно lsof
делать, но только для этого конкретного случая. Ищет все процессы для сокета FD. Для сокетов со свойством TCP
или TCPv6
(, которое доступно как мета-атрибут -файла system.sockprotoname
с использованием getfattr
, как найдено с lsof
, который будет использоватьgetxattr(2)
таким образом, чтобы по крайней мере отображать это сокет TCP ), проверьте, можно ли найти(sockfs псевдо -индекс )файловой системы в соответствующем сетевом пространстве имен tcp
илиtcp6
proc , и если нет отображает pid, fd и inode как кандидат 3 -uple.Только этот сценарий найдет и перечислит «дефектные» процессы.
findbadtcpprocs.sh
:
#!/bin/sh
find /proc -mindepth 1 -maxdepth 1 -name '[1-9]*' |
xargs -I{} find {}/fd -follow -type s 2>/dev/null |
while read procfd; do
type=$(getfattr --absolute --only-values -L -n system.sockprotoname $procfd | tr '\0' '\n')
if [ "$type" = "TCP" -o "$type" = "TCPv6" ]; then
inode=$(stat -L -c %i $procfd)
pid=$(echo $procfd | cut -d/ -f3)
if awk '$10 == inode { exit 1 }' inode=$inode /proc/$pid/net/tcp /proc/$pid/net/tcp6; then
fd=$(echo $procfd | cut -d/ -f5)
echo $pid $fd $inode
fi
fi
done
Этот скрипт можно использовать отдельно, чтобы просто найти процессы-кандидаты без дополнительной информации.
Затем следует gdb
сценарий, которому необходимо предоставить правильную fd информацию. Он подключается к процессу-кандидату и (сначала выделяет немного памяти, чтобы )запустить getsockname(2)
, отобразить связанный сокет (и освободить выделенные ресурсы )и освободить процесс.
getsockname.gdb
:
set $malloc=(void *(*)(long long)) malloc
set $ntohs=(unsigned short(*)(unsigned short)) ntohs
p $malloc(64)
p $malloc(4)
set *(long *)$2=64
p (int) getsockname($fd,$1,$2)
set logging file /dev/stdout
set logging on
if *((short *) $1) == 2
set $ip=(unsigned char *) ($1+4)
printf "%hu.%hu.%hu.%hu",$ip[0],$ip[1],$ip[2],$ip[3]
else
if *((short *) $1) == 10
set $ip6=(unsigned short *) ($1+8)
printf "[%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx]",$ntohs($ip6[0]),$ntohs($ip6[1]),$ntohs($ip6[2]),$ntohs($ip6[3]),$ntohs($ip6[4]),$ntohs($ip6[5]),$ntohs($ip6[6]),$ntohs($ip6[7])
end
end
printf ":%hu\n",$ntohs(*(unsigned short *)($1+2))
set logging off
call (void) free($2)
call (void) free($1)
quit
Наконец, связующий сценарий использует оба предыдущих сценария для упрощения работы. Это позволит избежать бесполезного подключения к нескольким процессам (или потокам ), использующим один и тот же сокет.
result.sh
:
#!/bin/sh
oldinode=-1
./findbadtcpprocs.sh | sort -s -n -k 3 | while read pid fd inode; do
printf '%d\t%d\t%d\t' $pid $fd $inode
if [ $inode -ne $oldinode ]; then
socketname=$(gdb -batch-silent -p $pid -ex 'set $fd'=$fd -x./getsockname.gdb 2>/dev/null) || socketname=FAIL
oldinode=$inode
fi
printf '%s\n' "$socketname"
done
Просто запустив это, вы получите все:
chmod a+rx findbadtcpprocs.sh result.sh
./result.sh
В качестве бонуса — простой воспроизводящий код на языке C, который создаст два процесса, использующих один и тот же сокет TCP, без использования listen(2)
для него. Использование:gcc -o badtcpbind badtcpbind.c
и./badtcpbind 5555
badtcpbind.c
:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <strings.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int sockfd;
struct sockaddr_in myaddr;
if (argc < 2) {
exit(2);
}
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket");
exit(1);
}
bzero(&myaddr, sizeof myaddr);
myaddr.sin_family = AF_INET;
myaddr.sin_addr.s_addr = INADDR_ANY;
myaddr.sin_port = htons(atoi(argv[1]));
if (bind(sockfd, (struct sockaddr *) &myaddr, sizeof myaddr) < 0) {
perror("bind");
exit(1);
}
#if 0
listen(sockfd,5);
#endif
fork();
sleep(9999);
}
пример:
#./badtcpbind 5555 &
[1] 330845
#./result.sh
108762 20 303507 0.0.0.0:0
330845 3 586443 0.0.0.0:5555
330846 3 586443 0.0.0.0:5555
(Да, по какой-то неизвестной причине здесь появляется процесс libvirtd
для создания сокета TCP, который не используется и попадает в первую строку результатов ).
Предостережения:
Вероятно, следует использовать язык лучше оболочки, чтобы обеспечить большую читабельность и эффективность.
определенно даже более колоритный, чем lsof
.
подключение к запущенному процессу, как здесь, имеет проблемы:
malloc()
или некоторые определения символов недоступны, тогда ). malloc(3)
или getsockname(2)
сбой ). последний скрипт считает sockfs иноды глобальными (, а не -сетевыми -пространством имен )уникальными, что я не пытался доказать, но скрипт упрощается.