1) Прежде всего, научить Linux работать с модемом
2) Создать NAT для раздачи интернета
3) Запихнуть всё это дело в автозагрузку
Итак, bash, wvdial и iptables под мышку — и поехали!
Подключение USB 3G-модема
Бывает и так, что в некоторых странах есть свои провайдеры 3G-интернета, которые не предоставляют настроек для подключения, используя Linux, что, в общем-то, и понятно — ‘популярность’ как провайдера, так и Linux даёт о себе знать. Не все конфиги есть ещё на сайтах, тем более — для отдельных программ. Итак, в Латвии, где я и проживаю. есть два провайдера — LMT и Bite. Оба они предоставляют беспроводной интернет через модемы Huawei, залоченные, естественно, на них, ну да не в этом дело. Ну так вот — необходимо обеспечить интернет всюду, где есть 3G, используя модем и сервер. Что же делать?
Прежде всего, воткнуть модем в ноут. USB-модемы определяются в Linux как устройства под адресом /dev/ttyUSB*, где * — порядковый номер устройства, обычно адрес выглядит как /dev/ttyUSB0.
root@localhost:/# ls /dev/ttyUSB* ls: cannot access /dev/ttyUSB*: No such file or directory
Ой. Что-то он не определяется. А проблема вот такая (обмусоленная уже тысячу раз): модем — это устройство типа “два в одном”. Почему? Он совмещает в одной флешке как собственно модем, так и встроенный накопитель с драйверами модема под Windows (я уже молчу про кардридер). В Linux по умолчанию включается режим диска, а не модема Для того, чтобы включить ещё и режим модема, нужно установить пакет usb-modeswitch. После этого нужно перезагрузиться и опять подключить модем, подождать секунд 10 и опять выполнить команду на вывод списка устройств модема:
root@localhost:/# ls /dev/ttyUSB* /dev/ttyUSB0 /dev/ttyUSB1 /dev/ttyUSB2
Когда вывод походит на этот, всё отлично и можно двигаться дальше. У нас есть три устройства. Нам необходимо лишь одно — под номером 0, остальные 2 мы не используем — они не для наших целей. Насколько мне известно, одно из них, скорее всего, используется для отсылки СМС, а второе — для просмотра уровня сигнала сети и прочего.
Теперь — дело за программой, которая подключит нас. Я буду использовать программу wvdial, дополнительно к ней нужно установить пакет ppp, если он ещё не установлен.
apt-get install ppp wvdial
Многие советуют использовать программу wvdialconf для настройки подключения, но в данном случае она нам не поможет. После установки нам нужно отредактировать файл /etc/wvdial.conf. Стираем из него всё содержание, затем разбираемся в формате файла. Я предоставлю рабочие конфиги для провайдера LMT с тарифом OKarte Internets datorā и модемом Huawei E173 и Bite с неизвестным тарифом и модемом Huawei E1550.
[Dialer lmt] Init1 = AT Init2 = AT&FE0V1X1&D2&C1S0=0 #Init3 = AT+CPIN="1219" Init4 = AT+CGDCONT=1,"IP","internet.lmt.lv" Phone = *99# ISDN = 0 Username = { } Password = { } Ask Password = 0 Modem = /dev/ttyUSB0 PPPD Options = noauth crtcts multilink usepeerdns lock defaultroute nobsdcomp nodeflate refuse-pap refuse-eap refuse-chap refuse-mschap +chap Idle Seconds = 3000 Modem Type = USB Modem Compuserve = 0 Auto DNS = 1 Dial Command = ATD Stupid Mode = 1 FlowControl = NOFLOW [Dialer bite] Init1 = AT Init2 = AT&FE0V1X1&D2&C1S0=0 #Init3 = AT+CPIN="1219" Init4 = AT+CGDCONT=1,"IP","internet" Phone = *99# ISDN = 0 Username = { } Password = { } Ask Password = 0 Modem = /dev/ttyUSB0 PPPD Options = noauth crtcts multilink usepeerdns lock defaultroute nobsdcomp nodeflate refuse-pap refuse-eap refuse-chap refuse-mschap +chap Idle Seconds = 3000 Modem Type = USB Modem Compuserve = 0 Auto DNS = 1 Dial Command = ATD Stupid Mode = 1 FlowControl = NOFLOW
Вкратце — файл разделён на секции. Каждая из секций отвечает за одну комбинацию модем-провайдер. Начало секции обозначается меткой [Dialer xxx], где ххх — это название метки, по которой мы будем указывать, какие именно настройки нужны для подключения. Если нам потребуются настройки LMT, мы наберём команду wvdial lmt, и будут использоваться настройки из секции [Dialer lmt] — суть понятна. Из этих настроек нам нужно обратить внимание на следующие:
InitX = AT-BLABLABLA
— AT-команды после InitX — те команды, которые wvdial отсылает модему перед тем, как поднять подключение.
#Init3 = AT+CPIN="1219"
— Эта настройка, если убрать # в начале, будет посылать модему команду ввода пин-кода. Если честно, желательно её отключить — у меня эта команда по непонятным причинам не работала корректно. Легче просто подключить модем один раз к компьютеру с Windows и отключить ввод пин-кода при подключении, используя программу, поставляемую с модемом.
Init4 = AT+CGDCONT=1,"IP","internet"
— Здесь прописывается адрес APN, который предоставляет провайдер. Нужно обратить внимание на две последних отделённых кавычками части. Первая — IP — указывает IP-адрес для подключения, если настройки провайдера подразумевают то, что используется IP-адрес APN. Если же используется буквенный адрес вида “internet” или “internet.lmt.lv”, в первой части нужно оставить “IP”, а во второй — прописать буквенный адрес, как это сделано в примере.
Phone = *99#
— Ну тут всё стандартно — этот номер телефона используют практически все провайдеры, и менять его в большинстве случаев не понадобится.
Username = { } Password = { }
Имя пользователя и пароль для подключения к интернету. Если их нужно оставить пустыми, оставьте там скобочки вида { }. Если нет — просто поставьте там имя и пароль, без скобочек.
Modem = /dev/ttyUSB0
Имя устройства, которое нам нужно использовать. В 99% случаев оно будет именно таким.
Остальные параметры могут быть другими в случае других модемов, но для вышеперечисленных двух комбинаций модем-провайдер всё работает без проблем.
Ещё раз расскажу о том, как правильно запускать подключение вручную. Достаточно одной команды — wvdial xxx, где ххх — это название провайдера из конфигурационного файла (для меня это либо lmt, либо bite.) Однако — при запуске wvdial ”занимает собой” всю консоль, не давая возможности запустить что-либо ещё. Кроме того — если вы запустите wvdial в окне SSH и тут же разорвёте сессию, то и wvdial завершится. Нужно либо постоянно держать сессию открытой, либо использовать screen, который в данном случае решает сразу две проблемы довольно эффективно — что и советую.
Что в идеале нужно? Также научиться просто и легко запускать эти программы. В использовании мной описанной схемы есть свои нюансы:
1) Соединение нужно каждый раз запускать вручную.
— Достаточно немного изменить конфигурационные файлы системы, а именно — тот же /etc/network/interfaces:
auto ppp0 iface ppp0 inet wvdial provider lmt #Поднимать интерфейс ppp0 автоматически #Для подключения вызывать команду wvdial с аргументом lmt. Естественно, аргумент будет меняться.
Для меня этот способ не подходит — он рассчитан на то, что провайдер не меняется, но большая вероятность, что это понадобится кому-то ещё. Да и не особо-то надёжно это работает, по моему опыту, лучше настроить udev. Для себя же я не нашёл подходящих решений — для этого надо было бы определять принадлежность вставленной сим-карты тому или иному провайдеру, а решение с использованием этого становится очень сложным.
Ну а если всё же надо быть постоянно подключённым, даже если что-то глючит и модем отключается от сети? Ну тогда поможет следующий скрипт. Он смотрит, есть ли wvdial в списке процессов, а если нет, то делает ifup ppp0, что в совокупности с вышеупомянутыми настройками в interfaces должно вызывать wvdial заново:
#!/bin/bash # (c)2009 John de Graaff, rewritten by CRImier # This script checks if wvdial is running. # If it's not, it brings ppp0 up and down. # It is assumed that ifup ppp0 starts wvdial if test "$(pidof wvdial)" != "" ; then exit 0 else logger "wvdial not running. Better restart ppp0." /sbin/ifdown ppp0 sleep 2 /sbin/ifup ppp0 logger "ppp0 restarted." exit 0
2) При включении ноутбука, если модем был подключен во время загрузки системы, иной раз случаются зависания, которые выражаются в следующем — при попытке подключения, используя wvdial, выходят строчки вида
--> Cannot open /dev/ttyUSB0: Device or resource busy
, и подключиться не удаётся. Лечится на один раз просто — нужно лишь вынуть и воткнуть модем, а затем запустить соединение вручную, но вы же понимаете, что при отсутствии физического доступа к компьютеру эта задача усложняется до невозможности.
— Пока что я не могу предоставить нормального решения, поскольку сам ещё не занялся этим. Предполагают, что это из-за того, что программа usb-modeswitch не отрабатывает корректно, если модем вставлен в компьютер при запуске системы. Видимо, нужно покопаться с udev или указать какие-либо особые параметры для usb-modeswitch.
3) В условиях плохого приёма соединение часто обрубается
— Всё довольно просто. Дело в том, что у портов ЮСБ есть ограничение на отдаваемый ток, при превышении которого, насколько я помню, порт отрубается. Видимо, в условиях плохого приёма сигнала сети модем пытается повысить мощность приёмника и передатчика, и случается так, что модем начинает потреблять больший ток, чем выдерживает порт — порт отключается, модем выключается, соедниение отрубается насовсем. Посоветовать могу лишь, к примеру, купить отдельный адаптер питания для модема и впаять его в кабель.
После того, как интернет появился на нашем сервере, остаётся лишь настроить раздачу интернета с модема по Wi-Fi сети.
NAT
Если у компьютера есть два сетевых интерфейса, это ещё не означает, что из коробки можно спокойно раздавать интернет с одного на другой. Однако — не всё так сложно, чаще всего требуется всего пара настроек. Конечно, эти настройки сложно запомнить, не вникая в суть каждой строчки, но ведь для этого есть эта статья! Я нашёл наиболее подходящий для этой ситуации и безглючный скрипт, не могу не дать ссылку на него, поскольку найденный на нём скрипт самый короткий и ясный из тех, что я встречал — остальные умудряются растянуть пару правил iptables на несколько страниц… Прежде всего, посмотрю, что в нём надо бы изменить под мои нужды:
Найденный скрипт
#!/bin/sh PATH=/usr/sbin:/sbin:/bin:/usr/bin # # delete all existing rules. # iptables -F iptables -t nat -F iptables -t mangle -F iptables -X # Always accept loopback traffic iptables -A INPUT -i lo -j ACCEPT # Allow established connections, and those not coming from the outside iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT iptables -A INPUT -m state --state NEW -i ! eth1 -j ACCEPT iptables -A FORWARD -i eth1 -o eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT # Allow outgoing connections from the LAN side. iptables -A FORWARD -i eth0 -o eth1 -j ACCEPT # Masquerade. iptables -t nat -A POSTROUTING -o eth1 -j MASQUERADE # Don't forward from the outside to the inside. iptables -A FORWARD -i eth1 -o eth1 -j REJECT # Enable routing. echo 1 > /proc/sys/net/ipv4/ip_forward
Хм-хм. Этот скрипт уже староват — iptables ругается на одну из команд и не хочет выполнять, да и тот путь, которым в статье скрипт пытаются поместить в автозагрузку, тоже работает не всегда на моей практике. Более того, есть проблема — этот скрипт отлично подходит для ситуации, когда ничего не собирается меняться. Если бы так и было, я бы поставил iptables-persistence и на этом закончил бы статью. А вот я собираюсь иногда получать интернет по интерфейсу ppp0, иногда — по eth0, а иногда — вообще по wlan1, причём менять интерфейс хочу одной консольной командой. Так, eth1 в примере — внешний интерфейс, а eth0 — внутренний. Заменим их переменными, чтобы при необходимости можно было поменять одну строчку, а не редактировать весь текст. Также я хочу, чтобы при перезапуске компьютера последний выбранный внешний интерфейс сохранялся. Что тогда? Нужно всё поменять!
Задачи:
- Принимать первый аргумент командной строки в качестве названия внешнего интерфейса, проверяя подлинность имени, используя команду ifconfig;
- Добавить сохранение выбранного интерфейса в какой-нибудь файл в /etc и сделать ключ выбора последнего интерфейса, а лучше — при отсутствии имени интерфейса как аргумента.
- Запихнуть это всё красиво в автозагрузку и в $PATH.
Что же вышло в итоге?
#!/bin/bash #NAT script from www.debian-administration.org, modified by CRImier # Exit status 0 if operation is correct # Exit status 1 if trying to use last interface used when running for the first time # Exit status 2 if interface doesn't exist EIF='' IIF='wlan0' PATH=/usr/sbin:/sbin:/bin:/usr/bin LOGFILE=/etc/nat-if.conf touch $LOGFILE # #Checking command-line arguments and setting $EIF variable according to them # if [ $1 == "" ] #If there's no arguments, just use previous settings. then EIF=`cat $LOGFILE` if [ $EIF == "" ] #Just check for an empty file! then echo "Please, specify interface name for first usage using 'firewall interface', e.g. 'firewall eth0'" exit 1 fi elif [ $1 == "help" ] #Output help message then echo "NAT script" echo "(c) www.debian-administration.org, modified by CRImier" echo "Usage: 'firewall interface', 'firewall info' or simply 'firewall' to use last interface firewall was set on." echo "Argument is external interface name, internal interface name is hard-coded in the script" exit 0 elif [ $1 == "info" ] #Print interface firewall is set on then cat $LOGFILE exit 0 else ifconfig $1 &>/dev/null if [ $? == 0 ] then #Interface name must be correct as ifconfig gives 0 exit code EIF=$1 echo $EIF > $LOGFILE else echo "Incorrect interface name" exit 2 fi fi # #$EIF is set correctly, let's apply the rules: # iptables -F iptables -t nat -F iptables -t mangle -F iptables -X iptables -A INPUT -i lo -j ACCEPT iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT iptables -A FORWARD -i $EIF -o $IIF -m state --state ESTABLISHED,RELATED -j ACCEPT iptables -A FORWARD -i $IIF -o $EIF -j ACCEPT iptables -t nat -A POSTROUTING -o $EIF -j MASQUERADE iptables -A FORWARD -i $EIF -o $IIF -j REJECT echo 1 > /proc/sys/net/ipv4/ip_forward echo "Firewall started."
Комментарии писал на английском — так привычнее. Если будут просьбы — могу и перевести.
Ну и не забываем обязательную часть:
chmod +x /etc/init.d/user-autorun
Окей, скрипт у нас готов. Как можно понять, вариантов вызова четыре — firewall (используется последний интерфейс), firewall наш_интерфейс, firewall info (выводит текущий интерфейс, на котором настроен NAT) или firewall help. Осталась лишь автозагрузка и $PATH.
echo $PATH >/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
Для того, чтобы вызывать скрипт командой firewall, не указывая местоположение, нужно запихнуть его в одну из папок, указанных в PATH. Я предпочитаю /usr/local/bin по религиозным соображениям. Полный путь к скрипту будет /usr/local/bin/firewall, а вот вызвать из консоли его всегда можно будет просто командой firewall.
Автозагрузка
А теперь — автозагрузка, с ней посложнее. Я сразу опишу создание скрипта автозагрузки, в который можно будет запихнуть всё, что угодно. Он будет стартовать вместе с системой, нооо…
Нельзя просто так взять и создать файл автозагрузки. Есть одна проблема — Debian с какого-то времени пересмотрел свои требования к файлам автозагрузки. Файл мало просто создать, его нужно ещё по-особому отформатировать:
- Первая проблема — это LSB headers. Это заголовок файла автозагрузки. Нужен он потому, что компоненты автозагрузки должны выполняться в определённом порядке, поскольку часть из них зависят друг от друга. Предположим, у вас есть два скрипта в автозагрузке — один из них должен будет монтировать сетевую папку, а второй — делать в неё резервную копию файлов. Естественно, что сначала нужно выполнить первый, а потом — второй, поскольку второй зависит от первого. Для указания таких зависимостей и используются заголовки загрузочного файла. Впрочем, будет достаточно того заголовка, который я выложу в образце файла автозагрузки.
- Вторая проблема — любой скрипт в автозагрузке при запуске системы вызывается командой /etc/init.d/script start, а при выключении компьютера — командой /etc/init.d/script stop. Нужно добавить условия для обработки этих случаев.
Я сделал просто — взял за основу скрипт из имеющихся в /etc/init.d/ — уж они-то должны быть созданы по правилам, потом изучил этот скрипт и вырезал из него всё ненужное. Осталось два места, которые нужно изменить — место для команд, которые выполняются при запуске системы, и место для команд, которые выполняются при выключении компьютера. Впрочем, сейчас всё увидите:
#!/bin/sh ### BEGIN INIT INFO # Provides: firewall # Required-Start: $network $local_fs $remote_fs # Required-Stop: $network $local_fs $remote_fs # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # X-Interactive: false # Short-Description: Start user autorun events ### END INIT INFO case "$1" in start) echo "Starting user autorun events" /usr/local/bin/firewall #Место для команд, которые должны выполниться при запуске системы ;; stop) echo "Stopping user autorun events" #Место для команд, которые должны выполниться при завершении работы системы #Останавливать NAT нет необходимости ;; *) echo "Usage: /etc/init.d/user-autorun {start|stop}" exit 1 ;; esac exit 0
Опять же, дать права на исполнение:
chmod +x /etc/init.d/user-autorun
В файле автозагрузки лучше указывать полный путь к исполняемому файлу, поскольку иначе при загрузке иногда возникают проблемы вида “firewall: command not found”.
Этот файл кладём в папку /etc/init.d/. Полный путь к нашему файлу автозагрузки — /etc/init.d/user-autorun. Осталось лишь указать системе, что нужно выполнять этот файл при загрузке:
update-rc.d user-autorun defaults
Эта команда заодно и проверяет, соответствует ли заголовок скрипта нужному, поэтому — если с этим будут проблемы, ничего в автозагрузку не поставится и придётся разбираться с ошибками. Всё, скрипт автозагрузки готов к работе и будет выполняться каждый раз при запуске системы, запуская скрипт маршрутизации. Конечно, в данном решении есть свои недостатки, вроде невозможности как-либо контролировать доступ пользователей к Интернету, кроме отключения-включения самого скрипта, но для случая переносного сервера плюс один и огромный — это просто работает, без вмешательства и стабильно, а альтернативные системы при надобности я ещё успею рассмотреть.
Удачной настройки!
Следующая статья, скорее всего, будет про написание простого веб-интерфейса на Python, используя web.py. Через этот интерфейс можно будет управлять NAT (правда, не превышая возможностей написанного скрипта), включать/выключать wvdial, отсылать смс и просматривать состояние модема… А также делать всё, до чего дойдут руки. Пока что пишу скрипт для взаимодействия с модемом и продумываю интерфейс таким образом, чтобы его было легко использовать даже на мобильных устройствах. Также в запасе есть почти готовая статья по настройке параметров энергосбережения ноутбука, используя cpufreqd. Стоит ли выкладывать её, будет ли актуально?
Аргументированная критика и дополнения к статье категорически приветствуются.
ссылка на оригинал статьи http://habrahabr.ru/post/188886/
Добавить комментарий