Сервер удаленного доступа с callback на FreeBSD


Сразу сделаю оговорку - статья не претендует на пособие или руководство.
В данном случае, я просто хочу поделиться своим личным опытом и опытом людей, которые мне помогали разобраться во всех тонкостях.

Задача возникла следующего характера: необходимо создать аналог виндового Remote Access Server под FreeBSD. В качестве оборудования использовалась машинка PIII-300/ 64/ 4.3G + PCI Serial card на 2 com-порта на чипе NETMOS NM(http://www.ivmm.com/eio/products_pci_fast_serial.html ). Дистрибутив взял FreeBSD 5.2.1 - на данный момент (март 2004) самый свежий.

Не буду описывать установку и пост установочный процесс, ибо этой информации вполне достаточно везде и на всех языках.
Ставил по минимуму - только то что необходимо: mc, sshd, порты.
Хочу обратить внимание лишь на поддержку в ядре сом-портовой карты на NM9835. Необходимо добавить или убрать комментарий для следующей строки:

device puc

Более подробно про поддержку разного железа можно почитать тут http://www.freebsd.org/relnotes/CURRENT/hardware/i386/support.html.
Никаких дополнительных опций в ядре больше не выставлял, разве что добавил firewall:

options IPFIREWALL
options IPFIREWALL_VERBOSE
options IPDIVERT
options DUMMYNET

После перекомпиляции и подстановки нового ядра, при загрузке системы (или после с помощь dmesg) видим такую строку:

puc0: <NetMos NM9835 Dual UART and 1284 Printer port>

Это наша карточка. После загрузки в /dev появятся cuaa4 и cuaa5 (помимо стандартных системных сом-портов cuaa0 и cuaa1). Можно цеплять к портам модемы.

На следующем этапе нужно решить, на чем делать сервер доступа. В начале я попробовал стандартную связку pppd + mgetty. В портах FreeBSD 5.2.1 есть pppd version 2.3 patch level 5, достаточно древняя, но более чем работоспособная и надежная. Также был установлен пакет /usr/ports/comms/mgetty+sendfax. Если есть необходимость построить просто сервер доступа без callback, я бы рекомендовал строить именно на
связке pppd + mgetty, хотя есть еще варианты с mpd и ppp. Именно pppd (kernel ppp) работает очень надежно и быстро. Но в моем варианте нужен
callback. Попытки найти подходящие патчи с поддержкой callback для pppd не увенчались успехом, а последняя версия pppd вообще не работает на FreeBSD ? т.е. разработчики не поддерживают данную операционную систему в новых версиях.

Остались варианты с ppp(user ppp) и mpd(Multi-link PPP daemon). Я выбрал ppp. Наверно потому что ничего доустанавливать не нужно.

Далее идет описание настройки связки ppp + mgetty.

1) правим /etc/rc.conf:
gateway_enable="YES"

Для клиентов, которые будут дозваниваться, именно эта машина будет шлюзом, поэтому включаем эту опцию. Если необходима поддержка
firewall-а, включаем еще и

firewall_enable="YES"
firewall_script="etc/firewall"

2) После установки mgetty+sendfax все конфиги лежат в /usr/local/etc/mgetty+sendfax/. Нас интересуют файлы login.config и mgetty.config. Приводим mgetty.config к следующему виду (хотя вполне возможны и другие варианты):

debug 4
fax-id 00 00 000000
speed 57600
direct NO
blocking NO
port-owner uucp
port-group uucp
port-mode 0660
toggle-dtr YES
toggle-dtr-waittime 500
data-only NO
fax-only NO
modem-type auto
init-chat "" ATS0=0Q0&D3&C1 OK
modem-check-time 3600
rings 1
answer-chat "" ATA CONNECT c
answer-chat-timeout 80
autobauding NO
ringback NO
ringback-time 30
ignore-carrier false
issue-file /etc/issue
prompt-waittime 500
login-prompt @!login:
login-time 240
diskspace 1024
notify faxadmin
fax-owner uucp
fax-group modem
fax-mode 0660

Добавляем в login.config следующую строку и закомментируем строку по умолчанию:

#/AutoPPP/ - a_ppp /usr/sbin/pppd auth -chap +pap login debug
/AutoPPP/ - - /usr/local/bin/ppplogin.sh

3) Создаем в /usr/local/bin файл ppplogin.sh следующего вида и делаем его исполняемым:

#!/bin/sh
exec /usr/sbin/ppp -direct callback

Данную информацию по связке ppp + mgetty удалось найти только здесь:


4) Добавляем в /etc/ttys наших порты чтобы они прослушивались mgetty на наличие входящих звонков:

## COM's for Mgetty
cuaa0 "/usr/local/sbin/mgetty" unknown on insecure
cuaa1 "/usr/local/sbin/mgetty" unknown on insecure
cuaa4 "/usr/local/sbin/mgetty" unknown on insecure
cuaa5 "/usr/local/sbin/mgetty" unknown on insecure

Делаем kill -1 1 и смотрим результат:

561 ?? I 0:00.07 /usr/local/sbin/mgetty cuaa1
592 ?? I 0:00.07 /usr/local/sbin/mgetty cuaa4
5517 ?? S 0:00.02 /usr/local/sbin/mgetty cuaa0
5518 ?? S 0:00.02 /usr/local/sbin/mgetty cuaa5

Должно быть так как приведено выше. Так же следует посмотреть файлы /var/log/mgetty.cuaa0 (1,4,5) на наличие работоспособных модемов. Если
все в порядке с модемами (на модеме должна гореть DTR), то должно быть что-то типа:

03/11 09:49:53 aa1 mgetty: experimental test release 1.1.30-Dec16
03/11 09:49:53 aa1 check for lockfiles
03/11 09:49:53 aa1 locking the line
03/11 09:49:56 aa1 lowering DTR to reset Modem
03/11 09:49:57 aa1 send: ATS0=0Q0&D3&C1[0d]
03/11 09:49:57 aa1 waiting for ``OK'' ** found **
03/11 09:49:57 aa1 mdm_send: 'ATI'
03/11 09:49:57 aa1 Generic Rockwell modem (56000)
03/11 09:49:57 aa1 mdm_send: 'ATI3'
03/11 09:49:57 aa1 mdm_send: 'ATI4'
03/11 09:49:57 aa1 additional info: 'SIC Vector +380 572 431680'
03/11 09:49:57 aa1 modem quirks: 0004
03/11 09:49:57 aa1 mdm_send: 'AT+FCLASS=2' -> OK
03/11 09:49:57 aa1 mdm_send: 'AT+FCLASS=0' -> OK
03/11 09:49:57 aa1 mdm_send: 'AT+FAA=1;+FCR=1' -> OK
03/11 09:49:57 aa1 mdm_send: 'AT+FBOR=0' -> OK
03/11 09:49:58 aa1 mdm_send: 'AT+FLID="00 00 000000"' -> OK
03/11 09:49:58 aa1 mdm_send: 'AT+FDCC=1,5,0,2,0,0,0,0' -> OK
03/11 09:49:58 aa1 waiting...

Если же не все нормально, тока в логе будет что-то типа:

03/11 09:53:52 aa0 mgetty: experimental test release 1.1.30-Dec16
03/11 09:53:52 aa0 check for lockfiles
03/11 09:53:52 aa0 locking the line
03/11 09:53:55 aa0 WARNING: DSR is off - modem turned off or bad cable?
03/11 09:53:55 aa0 lowering DTR to reset Modem
03/11 09:53:56 aa0 send: ATS0=0Q0&D3&C1[0d]
03/11 09:53:56 aa0 waiting for ``OK''
03/11 09:54:16 aa0 timeout in chat script, waiting for `OK'

5) Создаем пользователя, логин/пароль которого будет использоваться для аутентификации клиента. На самом деле, аутентификацию можно сделать (а может быть и лучше ? при наличии уже существующей ААА системы) на Radius или Tacacs, особенно если планируется большое число удаленщиков. В моем случае пользователей много не планировалось, поэтому остановился на стандартной Unix-аутентификации. Перед созданием пользователя, лучше добавить в /etc/shells путь к ppplogin.sh, который будет шеллом для пользователей на дозвоне:

/bin/sh
/bin/csh
/bin/tcsh
/usr/local/bin/ppplogin.sh

Если не добавлять последнюю строку, то при создании пользователя (adduser) система не даст выставить ему в качестве шелла ppplogin.sh, и
будет выставлен шелл по умолчанию ? sh. А потом придется менять руками шелл каждому пользователю.

Создаем пользователя. В итоге у нас получается:

manager1:*:1004:1004:PPP user:/home/ppp:/usr/local/bin/ppplogin.sh

6) Идем в /usr/share/examples/ppp и оттуда копируем в /etc/ppp файлы:

ppp.conf.sample -> ppp.conf
login-auth -> login-auth
ppp.secret.sample -> ppp.secret

Мне хватило этих 3-х файлов, т.е. я минимизировал все под свою задачу.
Файл login-auth я вообще не трогал. Из огромного количества примеров в ppp.conf оставляем только то, что нужно в нашем случае:

default:
set log Phase Chat LCP IPCP CCP tun command

callback:
enable pap passwdauth
enable proxy
set ifaddr 192.168.1.3 192.168.1.241-192.168.1.244
accept dns
set callback cbcp
set cbcp
set log +cbcp
set redial 3 1
set device /dev/cuaa0 /dev/cuaa1 /dev/cuaa4 /dev/cuaa5
set speed 115200
set dial "TIMEOUT 30 "" AT OK-AT-OK ATDT9w\T CONNECT"

Более подробно по некоторым строкам:

строка "set ifaddr" отвечает за выдачу адресов. Первый адрес - это адрес сервера (можно указать адрес сетевой карты), второй параметр - диапазон адресов которые будут выдаваться клиентам;

строка "set device..." указывает устройства, которые задействованы в обратном звонке - в моем случае все 4 порта.

В строке "set dial" я изменил таймаут с 10 на 30, и вместо ATDT поставил ATDT9w, т.к. у меня выход с мини-АТС на город через 9-ку.

Далее правим файл ppp.secret:

# Authname Authkey Peer's IP address Label Callback
manager1 * 192.168.1.251 * 222444
manager2 * 192.168.1.252 * *
lawer * *
lawer * *

В данном примере, пользователь manager1 имеет возможность использовать callback на фиксированный номер телефона, manager2 может указать номер телефона, на который ему перезвонить. У обоих эти пользователей статические адреса. У пользователей lawer1 и 2 не установлена
возможность callback-а и им выдаются динамические адреса из пула адресов, указанных в ppp.conf в параметре set ifaddr. Выдаваемые им адреса будут зависить от того, на какой порт они падают при дозвоне.

Клиентом у меня были Windows 2000 Priofessional, хотя я думаю, другие, более старшие товарищи, тоже будут работать. Настройки удаленного соединения стандартные, т.е. ничего настраивать не нужно вообще, все по умолчанию. Задается только номер телефона, логин и пароль. Звоним и смотрим лог /var/log/ppp.log (приведу только часть):

Mar 11 14:47:39 ras-server-server ppp[1494]: tun0: Phase: Pap Input: REQUEST (manager1)
Mar 11 14:47:39 ras-server-server ppp[1494]: tun0: Phase: Pap Output: SUCCESS
Mar 11 14:47:39 ras-server-server ppp[1494]: tun0: Phase: deflink: lcp -> cbcp
Mar 11 14:47:39 ras-server-server ppp[1494]: tun0: CBCP: deflink: SendReq(0) state = closed
Mar 11 14:47:39 ras-server-server ppp[1494]: tun0: CBCP: TYPE Server-spec
Mar 11 14:47:39 ras-server-server ppp[1494]: tun0: CBCP: DELAY 0
Mar 11 14:47:39 ras-server ppp[1494]: tun0: CBCP: deflink: State change closed --> req-sent
Mar 11 14:47:39 ras-server ppp[1494]: tun0: CBCP: deflink: RecvResponse(0) state = req-sent
...
Mar 11 14:47:39 ras-server ppp[1494]: tun0: CBCP: deflink: State change req-sent --> ack-sent
Mar 11 14:47:39 ras-server ppp[1494]: tun0: LCP: deflink: RecvTerminateReq(6) state = Opened
Mar 11 14:47:39 ras-server ppp[1494]: tun0: LCP: deflink: LayerDown
Mar 11 14:47:39 ras-server ppp[1494]: tun0: Phase: deflink: CBCP: Will dial back on 222444
Mar 11 14:47:41 ras-server ppp[1511]: tun0: Phase: Call peer back on 222444
Mar 11 14:47:53 ras-server ppp[1511]: tun0: Chat: deflink: Redial timer expired.
Mar 11 14:47:53 ras-server ppp[1511]: tun0: Phase: deflink: Connected!
Mar 11 14:47:53 ras-server ppp[1511]: tun0: Phase: deflink: opening -> dial
Mar 11 14:47:53 ras-server ppp[1511]: tun0: Chat: Phone: 222444
Mar 11 14:47:53 ras-server ppp[1511]: tun0: Chat: deflink: Dial attempt 1 of 1
Mar 11 14:47:53 ras-server ppp[1511]: tun0: Chat: Send: AT^M
Mar 11 14:47:53 ras-server ppp[1511]: tun0: Chat: Expect(30): OK
Mar 11 14:47:53 ras-server ppp[1511]: tun0: Chat: Received: AT^M^M
Mar 11 14:47:53 ras-server ppp[1511]: tun0: Chat: Received: OK^M
Mar 11 14:47:53 ras-server ppp[1511]: tun0: Chat: Send: ATDT9w222444^M
Mar 11 14:47:53 ras-server ppp[1511]: tun0: Chat: Expect(30): CONNECT

Mar 11 14:48:24 ras-server ppp[1511]: tun0: IPCP: IPADDR[6] 192.168.1.241
Mar 11 14:48:24 ras-server ppp[1511]: tun0: IPCP: PRIDNS[6] 192.168.1.2
Mar 11 14:48:24 ras-server ppp[1511]: tun0: IPCP: SECDNS[6] 255.255.255.255


Дозвон по кругу организуется средствами АТС - при наличии 4-х номеров настраивается переадресация звонка по сигналу занято с одного номера на другой и т.д. по кругу, а пользователям выдается один номер (скажем наиболее легко запоминаемый). При дозвоне, если одна линии занята, звонок перебросится на следующую линию, и т.д. пока не будет найдена свободная линия.

P.S. Надеюсь данная статья кому-нибудь поможет, если не разобраться, то быстро построить сервер удаленного доступа с минимальными усилиями. Все поправки и замечания принимаются.

Обновлено: 12.03.2015