Golang SSH загружает переменные среды LD_PRELOAD и LD_LIBRARY_PATH

Я пытаюсь подключиться к удаленному серверу с помощью Golang SSH package, но между моей рабочей станцией и этим удаленным сервером есть SOCKS.

Я могу подключиться к серверу, просто установив LD_PRELOAD и LD_LIBRARY_PATH, а затем запустив:

$ export LD_PRELOAD="/path/to/lib"
$ export LD_LIBRARY_PATH="/path/to/lib"
$ ssh user@hostname

Но когда я устанавливаю эти переменные в коде Go, это не работает:

os.Setenv("LD_PRELOAD", "/path/to/file")
os.Setenv("LD_LIBRARY_PATH", "/path/to/file")

Если я установлю эти переменные в коде Go и попробую следующее, все заработает:

ssh := exec.Command("ssh", "hostname")
output, _ := ssh.Output()
fmt.Println(string(output))

Для ssh PermitUserEnvironment установлено значение yes

Есть ли способ «заставить» Golang SSH использовать эти переменные среды?


person Felipe Siqueira    schedule 01.08.2017    source источник
comment
LD_PRELOAD и LD_LIBRARY_PATH не имеют ничего общего с самим ssh, то есть внедряют некоторые разделяемые библиотеки в ваш процесс openssh. Если вы не используете двоичный файл openssh, вы не сможете предварительно загрузить в него другую разделяемую библиотеку.   -  person JimB    schedule 01.08.2017


Ответы (1)


(Изменить: этот ответ не обязательно относится к Go 1.8 и выше. См. Комментарии для обсуждения)

LD_PRELOAD и LD_LIBRARY_PATH - переменные среды, обрабатываемые динамическим компоновщиком, когда программа запускается. Если вы установите эти переменные среды внутри программы, они не повлияют на саму программу, поскольку компоновщик их не видел.

С другой стороны, переменные среды будут влиять на внешние приложения, которые вы запускаете (например, команду ssh) изнутри программы, поскольку компоновщику дается управление для разрешения разделяемых библиотек, которые использует приложение.

Если вместо этого вы установите эти переменные среды перед запуском программы Go, я думаю, вы получите желаемый эффект. (Это применимо только в том случае, если скомпилированная программа связана с общей стандартной библиотекой C. См. @ Комментарии JimB ниже для более подробной информации.)

person svsd    schedule 01.08.2017
comment
Нет, это не даст желаемого эффекта, потому что Go не использует вызовы сокетов библиотеки C для переопределения. Скорее всего, программа Go не использует какие-либо разделяемые библиотеки C во время выполнения (хотя std lib использует cgo для преобразователя и пользовательского db, когда он включен) и может быть полностью статически скомпонован - person JimB; 02.08.2017
comment
@JimB спасибо, что указали на это! Я обновил свой ответ на основе вашего комментария после быстрой проверки того, что это действительно так. - person svsd; 02.08.2017
comment
Вы уверены, что? Функция Dial() в пакете ssh использует DialTimeout() из пакета net. Я написал простую программу, которая использовала DialTimeout(), и я смог использовать LD_PRELOAD для туннелирования через SOCKS прокси. (Это было в Linux с CGO_ENABLED, установленным в значение true / undefined. go build сгенерировал динамически связанный исполняемый файл, который я тестировал ..) - person svsd; 02.08.2017
comment
Ах да, я забыл, что нужно только перехватить Dial. Однако я думал, что текущие версии Go начали использовать по умолчанию собственный номеронабиратель, если этого не требуют локальные файлы конфигурации. Какую версию Go вы используете? (даже в этом случае вы все равно можете export GODEBUG=netdns=cgo заставить преобразователь cgo) - person JimB; 02.08.2017
comment
Я использовал go1.8.3 linux / amd64. В моей настройке преобразователь cgo используется по умолчанию, и я должен явно заставить его использовать преобразователь Go. Похоже, существует несколько условий, когда это может иметь место. - person svsd; 02.08.2017
comment
Хорошо, вот что я подумал. Поэтому, если вы хотите полагаться на LD_PRELOAD, вам нужно будет принудительно активировать распознаватель хоста во всех случаях, что вы можете сделать с помощью GODEBUG=netdns=cgo или построить с помощью тега netcgo. - person JimB; 02.08.2017