/* $Id: README,v 1.9 1997/05/03 11:57:20 lexa Exp $ */

	cyrproxy - перекодировщик кириллицы для текстовых протоколов.
		         Версия 1.4.0
		
	(C) 1996,1997, Alex Tutubalin <lexa@lexa.ru>

	частично использован код, написанный Vadim Kurland и Mike Shoyher

 Copyright Notice

Эта программа появилась после того, как меня не удовлетворили несколько 
программ аналогичного назначения. Не так важно почему, но пришлось писать
свою.

Мною были использованы куски из программы transl Вадима Курланда, втч
в текущей версии перекодировщики для Telnet и Gopher взяты из
transl без серьезных изменений. Функции, перекодирующие HTTP-протокол
написаны после того, как я посмотрел на аналогичные функции, написанные
Дмитрием Антиповым (dima@elvis.ru). Однако я совершенно не помнил как ко мне
попала программа Антипова и не был уверен, что куски из нее можно использовать,
поэтому весь HTTP-гейт написан с нуля.

Программа может быть свободно использована для некоммерческих  целей.
Если вы найдете в ней ошибки или захотите добавить новые возможности, 
то вы можете сделать это при соблюдении двух условий:
 - сохраните в тексте упоминание о моем авторстве
 - пришлете мне тексты ваших правок по адресу lexa@lexa.ru

Если вы хотите использовать программу в коммерческих целях, то свяжитесь
предварительно со мной (lexa@lexa.ru). Текущая моя политика такова - я не
беру денег за эту программу, но при необходимости могу попросить Вас о
'Reference' - письме (вероятно e-mail'овом) о том, что вы используете эту
программу в своей (коммерческой) организации. Это может помочь мне при 
очередном устройстве на работу.
Я не гарантирую, что эта "коммерческая полиси" будет неизменной всегда.

 BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.

0. Что входит в состав пакета программ.
 
 Изначально это была одна программа - cyrproxy, предназначенная для прозрачной
для пользователя перекодировки русских букв в почте, http, gopher, telnet.
Однако к настоящему моменту программ стало больше и приходится их документиро-
вать.
В комплект поставки входят:
 cyrproxy - собственно программа для перекодировки tcp-соединений. Далее в
 этом тексте описаны процедуры ее наладки, настройки и использования
 spy      - программа, которая скидывает протокол tcp-соединения в логфайлы.
 	    См. README.spy (он еще не написан :). Пришлось написать для 
	    отладки HTTP-протокола.
 discover - программа, восстанавливающая таблицу перекодировки по двум файлам
 	    с одинаковым содержанием, но в разных кодировках.
 cyrtrans - перекодировщик-фильтр (stdin->stdout)
 transfiles - скрипт, перекодирующий много файлов с помощью cyrtrans
 transtree - скрипт перекодирующий целиком дерево каталогов
 cyrwww   - WWW-интерфейс к cyrtrans. Позволяет сделать Paste текста в окно 
	броузера, нажать кнопку и получить перекодированный текст. Idea from
	Alexander Nikolaev (ati@samovar.ru). Сам я эту фичу не использую и не
	развиваю.
 
1.а Как это работает (в общих чертах).
 Программа cyrproxy запускается через inetd и перенаправляет входящее
 соединение на любой tcp-порт любой доступной по ip машины. Это выглядит 
 примерно так:

 $ tail /etc/services:

 smtp-cyr 10025/tcp  # SMTP-порт отличается от стандартного :)
 smtp-old 25/tcp    # А это порт, который эмулирует SMTP

 $ tail /etc/inetd.conf

 smtp-old stream tcp nowait root /usr/local/libexec/cyrproxy cyrproxy -p smtp-cyr -h localhost

 При входящем соединении на 25-й порт это соединение будет "прокинуто" на порт
 10025 машины localhost с (возможной) перекодировкой. 

1.б Принципы выбора перекодировок.
 Перекодировки управляются конфигурационным файлом (см ниже) и/или опциями 
 командной строки.  Выбор перекодировки между клиентом и сервером производится 
 на основе адреса клиента или адреса сервера (приоритет задается в 
 конфигурационном файле). Выбор на основе адреса клиента очевиден 
 (у всех клиентов разные адреса), выбор на основе адреса сервера 
 подразумевает,  что сервер имеет несколько ip-aдресов (разные интерфейсы 
 или aliases одного  интерфейса), скажем koi8.lexa.ru и win.lexa.ru, клиент 
 при запросе указывает один из этих адресов, а сервер (перекодировщик) 
 выбирает нужный вид  перекодировки по destination address.

 Все адреса (в конфигфайле и в командной строке) можно задавать либо в dotted 
 notation, либо в символьном (host.my.domain) виде. При старте перекодировщика 
 все символьные адреса преобразуются в IP-адрес и все сравнения производятся 
 над ними. Естественно, задание адресов в cимвольном виде подразумевает 
 работающий resolver. 

1.в. Gateways.
 Очевидно, что "простая побайтовая перекодировка" годится только для самых 
 простых _текстовых_ протоколов (SMTP, POP3, NNTP). Более сложные протоколы 
 (telnet, gopher, http) передают часть данных в двоичном виде, а 
 перекодировать  в них нужно только текстовую часть.  Для этого в программу 
 включены несколько  разных "Gateways". На сегодняшний день существуют такие:

 - default - перекодирует весь поток байт, не разбираясь с их содержанием
 - telnet  - поддерживает telnet protocol
 - gopher  - анализирует протоколо gopher
 - pop, smtp - практически аналогичны default, за тем исключением, что
	в строке Content-Type: text/plain; charset=some_charset, в строку
	сharset= принудительно вписывается заданное администратором значение
	charset. POP gateway делает эту операцию на потоке сервер->клиент,
        SMTP-gateway - на потоке клиент-сервер.
 - http    - анализирует содержимое http-потока данных и перекодирует только 
	данные text/* и application/x-www-form-urlencoded. При этом, если
 	для данного способа перекодировки описан 'emailcharset' (см ниже),
	то производится замена charset в HTTP-заголовке content-type
	(аналогично POP-gateway)
 
 gateway по-умолчанию - default. Все остальные могут быть выбраны либо опцией 
 командной строки, либо по TOS или номеру порта через описание в config file.

1.г Transparent Gateway
  Иногда "для гарантии" хочется точно ничего не перекодировать. Для этого 
  реализовано понятие transparent host. Идея заключается в том, что если 
  адрес destination совпадает с адресом, описанным как transparent host,
  то все перекодировки отключаются и сервер действует аналогично программе cat.

1.д Transparent Exec
  опция Transparent Exec (может быть задана только в командной строке)
  предназначена для того, чтобы запустить нужный сервис напрямую, а не 
  через TCP-проброс. Это может быть полезно, например,  в случае, когда 
  сам запускаемый сервис должен определить адрес Peer. Т.е., например, 
  если   на 25-м порту висит перекодировщик, который запускает sendmail 
  пробросом на другой порт, то в логах sendmail'а все 'relay' будут 
  указаны как localhost, что неприятно.
  Решение таково:
    - хост, который работает как MX (скажем mx.lexa.ru) объявить 
      TransparentHost'ом в конфигурационном файле cyrproxy.
    - при приходе клиента на этот хост вместо "себя" запускать (exec'ом) 
      sendmail, тогда все его записи в лог будут корректными
    - при приходе клиента на другие virtualhosts ({koi8,win}.lexa.ru) 
      - выполнять обычную перекодировку.

2. Installation.

a) Отредактируйте policy.h в соответствии с вашими вкусами (все опции
   там описаны).
   Отредактируйте пути до configfile и таблиц  в Makefile 
   Отредактируйте параметр SUBDIRS в Makefile (subdirs таковы:
   discover -- программа, которая по двум текстам в разных кодировках
	строит перекодировочную таблицу
   cyrcoder -- перекодировщик с командной строкой)
   Запустите 
		make all
   Должны получиться исполняемыe файлы с программами

б) Кроме всего прочего, получится файл config.gen Его стоит 
поредактировать в соответствии с реалиями (hostnames и прочее).

в) 'make install-bin', 'make install-config' и 'make install-tables' 
установят бинарь, конфиг-файл (скопируют config.gen в $CONF_FILE) 
и таблицы для перекодировки соответственно.
Эти три команды можно заменить одной -- make install


3. Таблицы перекодировки. 
 Это двоичные файлы длиной 256 байт. На каждый тип перекодировок
 (каждую кодовую таблицу) нужно два таких файла, один управляет перекодировкой 
 "от клиента", второй - "от сервера". Содержание этих 256-байтных файлов 
 должно отвечать такому замыслу: recoded_char = table[original_char];

4. Файл конфигурации 

(по умолчанию - /etc/cyrproxy.conf. Путь задается в makefile)
Синтаксис очень простой - либо комментарий (начинается с #, либо пустая строка,
либо option-name value(s)  

Возможные options  такие:

a) tabledir
tabledir - диpектоpия, в которой лежат таблицы перекодировки (умолчание
задается при комппиляции в Makefile:

tabledir /usr/local/share/proxy


б) encoding
Описание кодировок:
encoding name table_from_client table_to_client
name - имя кодировки, которое используется дальше, и два имени файлов,
	относительно $tabledir.
первый файл - перекодировка клиент->сервер, второй - наоборот. 
	Зарезервированное имя NONE означает, что перекодировку производить 
	не нужно (точнее, оно означает таблицу table[i] = i)

Пример:

encoding koi8 NONE NONE
encoding alt  koi8-alt alt-koi8
encoding win  koi8-win win-koi8

в) emailcharset
описание правила замены charset в строке Content-Type (POP, SMTP, HTTP)
emailcharset encoding_name server-charset client-charset

encoding-name - имя кодировки из описания encoding
server-charset - строка, которую SMTP_gateway подставит в 
	Content-Type: text/plain; charset=server-charset
client-charset - Charset, который увидит клиент при работе через POP3
	или HTTP gateway

Если для кодировки описан emailcharset, то HTTP-gateway будет менять
charset в Content-Type _только_ в заголовке и только если charset 
в заголовке уже имелся.
Для POP3 и SMTP протоколов все гораздо хуже. Т.к. за одну сессию может
быть передано больше одного письма, то я не вижу пристойного простого
способа отделять заголовки писем от всего остального. Т.е. если письмо
содержит (в теле) строку
Content-Type: text/plain; charset=some
То some будет заменен на charset, назначенный администратором.



Пример:
emailcharset win koi8-r windows-1251

г) transparenthost - см. раздел "5. Прозрачный фильтр"

Пример:
transparenthost ns.lexa.ru

д) encprecedence - в каком порядке выбирается тип кодировки.

Выбор кодировки может производиться по адресу клиента (Peer) и по адресу 
сервера (Virtual host). Порядок выбора определяется параметром encprecedence. 
Возможны два его значения - VP и PV, первое означает, что сначала происходит 
поиск по Virtualhost, если какая-то кодировка находится, то она и используется,
если нет, то происходит поиск по Peer, если не найдено ничего, то используется 
кодировка, заданная параметром default.
 Пример:

encprecedence VP

е) default - кодировка по умолчанию (см выше). 
 Синтаксис - default <name> (<name> - одно из определенных выше имен 
		кодировок).
 Например:

default koi8

ж) gwprecedence. - порядок определения типа gateway (cм выше). 
Gateway может выбираться по следующим параметрам:
 - задание в командной строке (при этом содержимое config-file игнорируется)
 - по номеру порта (имена портов пока не поддерживаются)
 - по значению поля TOS (Type of service) в TCP-пакетах.

Параметр gwprecedence может иметь два значения PT (сначала проверять номер 
порта, а потом TOS) и TP (сначала TOS, а потом номер порта).

gwprecedence  PT

з) option
 - ассоциирует gateway и номер порта или значение TOS.
 Из примеров все понятно (после слова протокол идет одно из названий 
 gateways - telnet, gopher, http)

option port 23 protocol telnet
option port 70 protocol gopher
option port 8080 protocol http
option tos  16 protocol telnet

и) peer - ассоциирует адрес клиента и кодировку. Используется если _все_ 
программы у клиента используют одну кодировку.

Синтаксис:
peer <address> <encoding>
где <address> - IP-адрес или domain name
<encoding> - одна из кодировок, описанных выше.

Например:
peer 1.2.3.4 win

к) Virtualhost - ассоциирует адрес сервера и кодировку. Рекомендуется к 
использованию - используя virtualhost можно заставить работать у клиента 
программы в _разных_ кодировках.
Синтаксис:
virtualhost address encoding
где address  - один из локальных адресов сервера (dotted notation or 
		domain name)
encoding - одно из имен кодировок.

Например:

virtualhost win.lexa.ru  win

5. Параметры командной строки.

Запуск программы  осуществляется через inetd. В командной строке задаются 
такие параметры:
а) Обязательные параметры:
 -p port - имя (из /etc/services) или номер порта, на который будет осуществлен
   "проброс"
 -h host - имя или адрес хоста, на который будет осуществлен проброс.

б) Необязательные:
 -c configfile - использовать configfile вместо файла по умолчанию 
 (файл по умолчанию задается в Makefile, в дистрибутиве это /etc/cyrproxy.conf)
 
 -t timeout (в секундах) - задает таймаут для убиения соединений (соединение 
     будет убито, если за это время по нему не проехало ни одного байта)
 
 -g gwname (gwname - одно из слов default, telnet, gopher, http) - 
	использовать указанный gateway, а не искать его по номеру порта/TOS
 
 -e encname - явно задает кодировку клиента и выключает поиск по конфигфайлу.

  -T - включает режим Transparent Host для всех сочетаний адреса клиента 
	и сервера.

  -R - включает режим Transparent Exec. В этом режиме вместо transparent host 
     mode ( не важно, заданной опцией -T или  выбранной по destination address)
     перекодировщик выполняет execp() c такими параметрами:
     имя исполняемого файла - первая лексема после опции -R
     аргументы командной строки (argv[0]...) - все прочие параметры, до конца 
     командной строки перекодировщика.

6. Некоторые замечания.
 Может получиться так, что при одинаковой собственно перекодировке, вам
 нужно разное поведение Gateways в зависимости от клиентского софта. Скажем,
 для части софтов нужно менять charset= в E-mail и HTTP, а для части нет.
 Кажущееся противоречие обходится очень просто: вы описываете две различных
 (по именам) кодировки с одинаковыми таблицами, а правила для них задаете 
 разные. Примеры:

 а) Установить замену charset для одного клиента (по адресу) персонально:

 encoding win  win-koi8 koi8-win 
 encoding win2  win-koi8 koi8-win 
 emailcharset win2  koi8-r windows-1251
 encprecedence PV
 peer 1.2.3.4 win2
 virtualhost win.my.domain win


 б) Два виртуальных хоста с различным поведением:

 encoding win  win-koi8 koi8-win 
 encoding win2  win-koi8 koi8-win 
 emailcharset win2  koi8-r windows-1251


 virtualhost win.my.domain win
 virtualhost win-2.my.domain win2



7. Different software notes

а) sendmail.
 К сожалению, я не нашел способа подвесить sendmail на другом порту с 
сохранением функциональности. Проблема заключается в том, что он вешается 
демоном на port=getservbyname("smtp") и ходит на тот же порт других хостов.
Поэтому _нельзя_ переопределить номер порта smtp в /etc/services.
Решение этой проблемы таково (в терминах /etc/services и /etc/inetd.conf):

$ tail /etc/services
 smtp	25/tcp
 smtp2  10025/tcp # этот номер может быть любым незанятым

$ tail /etc/inetd.conf
 # Проброс порта 25 на порт smtp2
 smtp	stream tcp nowait root /sbin/cyrproxy cyrproxy -p smtp2 -h localhost
 # запуск sendmail в inetd mode
 smtp2  stream tcp nowait root /usr/sbin/sendmail sendmail -bs

Возможное решение этой проблемы заключается в том, что:
 - при описании мэйлера smtp (или того, который занимается посылкой почты во 
   внешний мир) явно задается номер порта 25, порт smtp переопределяется,
   sendmail подвешивается демоном на этом переопределенном порту, а со старого 
   (25-го) порта делается проброс на новый.
 Но я так еще не делал за ненадобностью.

Совместно с sendmail полезно использовать опцию -R перекодировщика, это 
позволяет иметь корректные адреса relays в логах и позволяет работать в secure 
mode (i.e. проверять соответствие HELO и адреса peer).

б) HTTP-servers.
 Текущая версия httpGW работает только как перекодировщик, но не работает как 
 proxy.  Поэтому ее приходится использовать совместно с каким-то из 
 http-proxies (Squid, Harvest, CERN, Apache 1.1).
 Идея заключается в том, что WWW-proxy подвешивается, скажем, к порту 8000, 
 а перекодировщик - к порту 8080 ( -p 8000 -h localhost).
 Соответственно, WWW-browser'у нужно указать имя одного из virtualhosts 
 в качестве адреса Proxy и порт 8080 как имя порта.
 
 С помощью этого перекодировщика можно, также, русифицировать "отдельно стоящий
 WWW-server". Это можно сделать, например, явным указанием типа gateway и 
 кодировки в командной строке перекодировщика в inetd.conf. В предположении, 
 что HTTP-сервер "расположен" на порте 80, командная строка может выглядеть как
  -p 80 -h localhost -e win -g http  - для перекодировщика на 'Windows-порту'
  -p 80 -h localhost -e msdos -g http  - для перекодировщика на 'MSDOS-порту'

 Мне так приходилось делать, но вообще для "русификации отдельно стоящего 
 сервера" cyrproxy не предназначена по тривиальной причине - она не ведет
 http-логов, а в логах сервера будет только адрес localhost. Рекомендую
 не забивать себе голову :), а взять 'Russian Apache' by Dmitry Kryukov 
 (dvk@stack.net) and Alex Tutubalin с http://apache.lexa.ru/ и использовать 
 его - для этой цели он существенно пригоднее

в) POP3.
 Никаких особых проблем или замечаний.

г) Telnet.
 В текущей версии использован telnetGW Вадима Курланда. Он довольно странно 
 работает с telnet от FreeBSD, но таки работает.

д) Gopher. 
 Извините, но мне не на чем попробовать. Использован переработанный gopherGW 
 Вадима Курланда, однако я его не проверял.


8. Feedback. 


 Помощь и поддержка. 

 Никакой поддержки и помощи я никому не обещаю. Но если
 вы таки решите ее у меня получить, то не нужно присылать мне письмо из
 одной строчки "твоя программа под ZUINIX не работает" (почему-то половина
 писем - именно такая :). Чтобы реально помочь, мне нужно знать гораздо
 больше:
 а) если программа не собирается. Мне нужно знать версию OS, версию
  компилятора, версию make и видеть те сообщения об ошибках, которые
  выдает компилятор, make итп (т.е. эти строчки). Только не нужно 
  присылать графическую копию экрана, шлите текст.
 б) если программа не работает так как нужно. Раскомментируйте строчки 
 про DEBUG_LOG и NETWORK_DEBUG в policy.h и пересоберите cyrproxy.
 Пришлите мне выдержку из лога, cyrproxy.conf и описание проблемы.
 Не забудте сообщить  версию OS,  версию компилятора. 


 Bugfix, перенос под другие OS итп.

 Если вы нашли явную багу, перенесли cyrproxy под какую-то OS 
 или добавили новую feature - не стесняйтесь, пришлите ваши 
 изменения мне. Очень вероятно, что эти изменения (скорее всего, правда,
 в сильно измененном виде) будут включены в очередную версию cyrproxy.

 Я буду рад услышать любые пожелания и предложения ( но не факт, что буду
 их воплощать). На настоящий момент запланированы следующие features:
 - конфигурация через autoconf/configure
 - корректная отработка Accept: в HTTP 
 - Возможность подключения внешних gateways

 Пишите мне на lexa@lexa.ru

 9. Home site.
  Новые версии программы будут появляться на 
  ftp://ftp.lexa.ru/pub/domestic/lexa.
  Анонсы помещаются в relcom.unix (FIDO: RU.UNIX)

 10. Ожидаемые баги :)
  Я не имею возможности проверить таблицы для Macintosh, которые мне прислали.
  Прислали мне их со словами "С Eudora работает, а с Netscape - нет". Если у 
  вас есть другие таблицы -- пришлите их мне. Лучше всего -- сразу полный набор
  (mac-iso, mac-alt, mac-win, mac-koi8) :)

 11. Благодарности
 Многие люди помогли мне найти многие баги. Я не в состоянии вспомнить всех, 
 поэтому  если вы не попали в этот список - не обижайтесь. 
 Особую помощь оказали:
 Mike Shoyher <msh@alina.ru>
 Dmitry Barabanov <dmitry@irex.ru>
 Bill Fick <fick@glas.apc.org>
 Alexey Pialkin <pialkin@abel.pdmi.ras.ru>
 ...
 и многие другие.
 

 Regards,
 Alex Tutubalin, lexa@lexa.ru				3-May-1997
 
