# $Id: cwrsync.htm,v 1.12 2010/01/28 13:39:16 aost Exp $
В связи с бурным развитием домашних ethernet-сетей и широко распространенным в 
таких сетях перехватом трафика, в полный рост встала задача - найти простую и 
в то же время безопасную замену связки ftp + Far (или другой ftp-клиент), которой 
пользуются многие web-разработчики.

Сначала была сделана попытка зашифровать только момент передачи пароля по ftp 
(этот метод описан в одной из статей на opennet.ru), но мне метод не понравился. 
Затем я обратил внимание на утилиту rsync (http://rsync.samba.org) и ее win32 
аналог, который практически штатно умеет работать используя авторизацию по ssh 
ключам ( putty - в случае win32 системы ), защищенности которого под большинство 
задач хватает.
 
Для защиты от прямого доступа снаружи - демон rsync "вешается" на хорошо известный 
всем адрес 127.0.0.1 (внутренний кольцевой интерфейс), так что при любых уязвимостях 
программы, он недоступен извне, а по ssh мы пускаем только доверенных пользователей.


           Как все это должно работать.


Что нужно для запуска всей этой схемы:

 - cwRsync_2.0.10_Installer.zip (http://www.itefix.no/i2/cwrsync) - устанавливаем с настройками по-умолчанию.
 - id_rsa.ppk - putty private ssh key, помещаем в директорию, куда установили cwRsync.
 - test.cmd   - создаем и помещаем в любую удобную директорию, откуда будем его вызывать.
 - FarMenu.Ini - помещаем в рабочую директорию, где будет лежать код сайта и исправляем там имя сайта.


Работа логически делится на две части. 

           1. Подъем ssh туннеля до сервера:

При запуске командного файла test.cmd делается маппинг порта 873 удаленной стороны 
(rsyncd) на локальный адрес/порт, куда мы и будем ходить в дальнейшем.

"C:\Program Files\cwRsync\bin\plink.exe"  -i "C:\Program Files\cwRsync\id_rsa.ppk" \
	-L 873:127.0.0.1:873 user@121.121.121.121 -T -N

Сама по себе технология туннелирования других приложений через установленное ssh-соединение
применяется достаточно широко. Так, например, "проброс" соединения к терминальному серверу, 
находящемуся внутри сети по адресу 192.168.0.1, выглядит примерно так:

"C:\Program Files\cwRsync\bin\plink.exe"  -i "C:\Program Files\cwRsync\id_rsa.ppk" \
	-L 33892:192.168.0.1:3389 user@121.121.121.121 -T -N

Почему используется "маппинг" удаленного порта 3389 на локальный порт 33892? Потому, что на локальной
машине стандартный порт 3389 может быть уже занят местными службами. Кроме того, по сложившейся
традиции на юникс-системах, порты ниже 1024 - разрешены к открытию только привилегированному 
пользователю, т.е., например "зацепиться" за веб-сервер (IIS), стоящий внутри сети ( 80 - 80 ) 
простому пользователю не удастся - делается традиционный маппинг 8080:192.168.0.1:80.

Во избежание произвольных коннектов клиента ко всем машинам внутренней сети - со стороны сервера 
в файле authorized_keys пишется (без пробелов!) что-то типа:

permitopen="192.168.0.1:3389",no-pty,command="/usr/bin/perl -e '$|=1; srand; while (1) {print int(rand(10)); sleep 59}'" ssh-dss AAAAB5...21S==


           2. Собственно работа с rsync:

==== FarMenu.ini
FarMenu.Ini 
-:
L:  List existing rsync modules
    "C:\Program Files\cwRsync\bin\rsync" -l 127.0.0.1::
-:
D:  rsync from remote HOST to local
    "C:\Program Files\cwRsync\bin\rsync.exe" -avz user@127.0.0.1::blockname .
-:
U:  rsync from ME to remote HOST
    "C:\Program Files\cwRsync\bin\rsync.exe" --exclude FarMenu.Ini -avz . user@127.0.0.1::blockname
==== FarMenu.ini

Поместив FarMenu.ini в рабочую директорию, мы можем по нажатию кнопки F2 выбрать: 
либо мы синхронизируем данные "от сервера к себе", либо наоборот. Этот файл можно
редактировать обычным редактором, добавляя, при необходимости, другие ключи. В 
новой рабочей директории на локальной машине нужно поменять имя блока "blockname" 
на соответствующее.

rsync сам следит за синхронностью файлов, т.е., можно запустить синхронизацию несколько раз, но
реально трафик пойдет только один раз - когда файлы будут засинхронизированы.

rsync позволяет копировать файлы между хостами, но, по сравнению с простым копированием, 
ускоряет процесс т.к. передает только измененные части (хитрый алгоритм на основе 
сравнения контрольных сумм частей файлов). 

Позволяет копировать ссылки (links), специальные устройства (device), владельца и группу 
файла, права доступа, использовать в качестве транспорта как rsh, так и ssh. При копировании
файлов с win32 машины на unix-сервер - права на файлы получаются 600! Unix-дистрибутив 
rsyncd включает сервер rsyncd (доступ анонимный или с аутентификацией), порт 873/TCP. Имя файла 
записывается в формате: [[user@]host:]file, либо [[user@]host:]:block, описанный в конфиге rsyncd.

Если файл назначения является именем директории, то исходные файлы копируются в нее. Если 
имя исходной директории завершается обычной косой чертой, то копируется содержимое директории, 
а не сама директория (почувствуйте разницу ;). Относительные имена отсчитываются относительно 
домашней директории соответствующего пользователя на соответствующем хосте. 

Если в качестве параметров указано только имя удаленного блока/файла/директории (без указания 
локального пути), то выдается соответствующий листинг, если указан адрес с двумя двоеточиями 
(127.0.0.1::) - то выдается список названий и комментарии блоков. Нельзя копировать с одного 
удаленного хоста на другой - rsync должен быть установлен на обоих концах. 

Опции:

    * опции диалога:
          o -v (увеличить болтливость: один раз - имена передаваемых файлов; два раза - имена пропускаемых файлов; три раза - отладочная печать)
          o -q (совсем тихо)
          o --version
          o --progress (только в сочетании с -v)
          o --stats (статистика эффективности алгоритма)
          o --help
          o -n (не делать реальной пересылки, только отчет о предполагаемых действиях)
    * какие файлы включать в список проверки перед пересылкой
          o -r (рекурсивное копирование)
          o -x (не пересекать границы файловой системы при рекурсии)
          o --exclude=шаблон
          o --cvs-exclude (стандартный набор исключений, используемый cvs: *~, *.bak, *.o, core и т.д., включая содержимое файлов .cvsignore)
          o --exclude-from=имя-файла
          o --include=шаблон
          o --include-from=имя-файла
    * правила проверки на совпадение файлов
          o -I (пересылать файл даже если длина и время модификации совпадает на обоих концах)
          o --size-only (определять необходимость пересылки только по совпадению размеров файла)
          o --modify-window=секунд (если разница времени модификации меньше указанного числа, то файлы считаются одинаковыми; по умолчанию - 0)
          o -c (на исходном конце считается контрольная сумма (MD4) файла, на приемном конце она сравниваются с контрольной суммой локальной копии; если суммы совпадают, то пересылка не происходит)
          o -u (не изменять, если приемный файл новее исходного)
          o --existing (изменять только существующие файлы)
          o -W (копировать файлы целиком, не задействуя алгоритм сравнения)
    * backup (сохранять старую версию изменяемого файла)
          o -b (делать backup, суффикс по умолчанию - '~')
          o --suffix=суффикс (суффикс для backup)
          o --backup-dir (backup в указанную директорию)
    * обработка ссылок
          o -l (сохранять символьные ссылки; пропускаются по умолчанию)
          o --copy-links (обрабатывать символьные ссылки как обычные файлы)
          o --copy-unsafe-links (копировать ссылки, указывающие вовне исходного дерева)
          o --safe-links (игнорировать ссылки, указывающие вовне приемного дерева, и абсолютные ссылки)
          o -H (воссоздавать жесткие ссылки на приемном конце; срабатывает только если оба (а больше?) файла входят в список пересылки)
    * сохранение атрибутов файла
          o -a (архивный режим: синоним -rlpogDt)
          o -p (сохранять права доступа)
          o -o (сохранять владельца файла; только для root)
          o --numeric-ids (вместо имени владельца и группы пересылается uid и gid)
          o -g (сохранять группу файла; получатель должен быть членом группы)
          o -D (сохранять устройство; только для root)
          o -t (сохранять время модификации; очень рекомендуется, если предполагается повторная пересылка)
    * правила удаления
          o --delete (удалять на приемной стороне файлы, не существующие на исходной стороне)
          o --delete-excluded (удалять, если "несуществование" вызвано действием шаблона исключения)
          o --delete-after (удалять после передачи, а не до)
          o --ignore-errors (удалять даже при ошибках ввода/вывода)
          o --max-delete=число (не удалять более указанного числа файлов)
          o --force (удалять непустые директории; действует также при замене директории обычным файлом с тем же именем)
    * -R (относительные имена: в действительности передает имя файла из командной строки целиком вместе с именем директории, а не только файловую часть имени; осторожнее с символьными ссылками!)
    * -S (эффективно обрабатывать файлы с дырками)
    * --block-size=размер (размер блока для сравнения контрольных сумм - 700)
    * -e ssh (транспортный уровень; можно через переменную окружения RSYNC_RSH)
    * --rsync-path=путь (путь к rsync на удаленном хосте)
    * --partial (сохранять частично переданные файлы)
    * --timeout=секунд (по умолчанию 0 - бесконечность)
    * --temp-dir=директория (где хранить файлы во время пересылки)
    * --compare-dest=директория
    * --compress (gzip, но используется информация о пересылаемых структурах, что при большом числе неизмененных файлов будет полезно)

Синтаксис шаблона (и не лениво людям придумывать свои правила описания шаблонов?):

    * если шаблон начинается с обычной косой черты, то он сопоставляется с началом имени файла, иначе с концом имени файла
    * если шаблон завершается косой чертой, то он сопоставляется только с директорий
    * метасимволы *, ? и [ действуют как в шаблонах shell
    * если в шаблоне имеются две ** подряд, то все метасимволы могут сопоставляться с косой чертой, иначе их действие останавливается косыми чертами
    * если шаблон содершит нефинальную косую черту, то он сопоставляется полному имени файла, иначе последнему компоненту; только учтите, что алгоритм работает рекурсивно

Переменные окружения:

    * RSYNC_RSH=ssh
    * CVSIGNORE=шаблон

Типичный пример использования без сервера (через ssh):

    * rsync -e ssh -vacu user@host:dir/  .
    * rsync -e ssh -vacu --exclude '.*.swp' .  user@host:dir/
    * rsync -e "ssh -l user -i /home/user/.ssh/id_rsa" --bwlimit=200 -vacu host:dir/  .

Передача данных (с докачкой --inplace) на удаленную машину
    * rsync -e "ssh -l ${USER} -i ${KEY}" ${OPTIONS} --inplace -vact ${NEAR_DATA} ${REMOTE_IP}:${FAR_DATA}


Обратите внимание на завершающий слеш, так как он имеет значение для rsync: если на конце 
исходной директории стоит "/", то это означает копирование содержимого директории, отсутствие 
"слеша" означает копирование (создание) директории и копирование ее содержимого. 

                   Авторизация и права файлов.

В случае работы windows клиентов в файл конфигурации демона полезно добавить строчку, автоматически меняющую 
права загружаемых на сервер файлов: incoming chmod = g+r,Dg+x,Fgo-x, иначе права почему-то получаются 600. 
По отзывам, так же помогает использование ключика -p (--perms preserve permissions).

Для дополнительного разделения полномочий можно использовать внутренних пользователей rsync, не совпадающих
с системными и, судя по примерам, различных для каждого модуля. 

    [cvs]
    path = /data/cvs
    comment = CVS repository (requires authentication)
    auth users = tridge, susan
    secrets file = /usr/local/etc/rsyncd.secrets
    
Файл /usr/local/etc/rsyncd.secrets содержит имена и нешифрованные пароли 
(должен быть ограничен для чтения группе и другим пользователям!!!):

    tridge:mypass
    susan:herpass

Для автоматического ввода пароля на стороне клиента - можно использовать опцию --password-file и файл, 
содержащий [b]только незашифрованную строку пароля[/b].

    $ rsync --password-file ./mypass.txt test@192.168.0.1::test_area
    password file must not be other-accessible
    continuing without password file





Нестандартное использование rsync при туннелировании через ssh на третью машину.

Часто возникает ситуация, когда REMOTE_001 у нас торчит наружу, а REMOTE_002 "спрятана" 
где-то внутри сети. Чтобы притащить файлик с REMOTE_002 надо:

- поднять ssh туннель командой:

   ssh -L 127.0.0.2:22022:${REMOTE_002}:22 ${REMOTE_001}"

- набрать примерно такую команду синхронизации:

   rsync -e "ssh -p 22022"  --progress -vact 127.0.0.2:/data/Example/from_remote.tgz ./.