Пускаем QEMU в сеть

(Это перепечатка статьи в моем ЖЖ'шном блоге)

Что есть: Linux Slackware 12, QEMU 0.9.1, live-cd с Линуксом (я взял Gentoo install-x86-minimal-2007.0 - загружается быстро, X-ов нет, links имеется (он мне понадобился для тестирования)), реальный (физически существующий) интерфейс с подключением к Интернет (у меня сетевая карта eth0, подключенная к Спарку).

Итак, приступим.

Настрока ядра реальной системы

Нам нужны следующие опции:


Networking Options -> Network packet filtering framework - поддержка iptables (конкретно - ветка IP: Netfilter configuration - Netfilter для IPv4, обратите внимание на поддержку NAT)
Device Drivers->Network device support->Universal TUN/TAP device driver - эмуляция сетевых интерфейсов (отметьте как M).


После компиляции мы получим несколько модулей (если, конечно, все предлагаемые опции мы отмечали как M). Модули для iptables подгружаются самой iptables. Модуль для TUN/TAP называется tun, его подгружать мы будем сами.

Установка UML Utilites (User-mode Linux Utilites) и Iptables

UML Utilites предоставляет программку под названием "tunctl", которая, собственно, и создает виртуальный сетевой интерфейс.

Проверьте, есть ли эта программка у вас ("tunctl BLAH BLAH BLAH" выведет краткую справку). Если tunctl у вас не наблюдается - прошу на сайт проекта. Загрузить исходники можно отсюда (нас интересует подкатегория "tools"). (сайт у UML ... довольно not user-friendly!)

Iptables - суть есть firewall. Для тех, кто не в танке - прост как дифференциальное уравнение. Страница программы. Я использую iptables v1.3.8.

Создаем псевдо-сетевую_карту

$real_ip - ip адрес нашего реального интерфейса (в моем случае - eth0). Это адрес реальной системы во внешней сети.
$host_ip - ip адрес виртуального интерфейса в реальной системе.
$virt_ip - ip адрес виртуального интерфейса в виртуальной системе (загруженной на сэмулированном с помощью QEMU компьютере).
$broadcast - широковещательный адрес для сети, содержащей $host_ip и $virt_ip.

Между виртуальным и реальным интерфейсом в реальной системе необходимо будет настроить переброску (форвадинг) пакетов.

Сделайте:


host_ip='192.168.0.2'
virt_ip='192.168.0.3'
real_ip='IP_РЕАЛЬНОГО_ИНТЕРФЕЙСА'
broadcast='192.168.0.1'


Создаем виртуальный интерфейс:


ic=`su -c 'modprobe tun && tunctl -b -u $NAME && chmod 666 /dev/net/tun'`


Где $NAME - имя пользователя, который выполнил данную команду.

В ic будет записано имя созданного интерфейса. Скорее всего это будет "tap0".

(Кстати, вам необходимо знать пароль к учетной записи root'а ;-) )

Поднимаем виртуальный интерфейс в реальной системе:


su -c "ifconfig $ic up $host_ip netmask 255.255.255.0 broadcast $broadcast && echo 1 > /proc/sys/net/ipv4/ip_forward"


Настройка iptables

Файл /proc/sys/net/ipv4/ip_forward содержит одну единственную цифру. 0 - переброска пакетов между интерфейсами запрещена, 1 - разрешена.


su -c "iptables -t nat -L && iptables -t nat -A POSTROUTING -s $virt_ip -j MASQUERADE"


Устанавливаем маскарадинг для всех пакетов, пришедших с $virt_ip (с виртуальной системы). Команда "iptables -t nat -L" выводит текущее состояние таблицы nat.

Запуск QEMU


mac=$(echo -n EE:AE:B0:BF; for i in `seq 1 2`; do echo -n `echo ":$RANDOM$RANDOM" | cut -n -c -3`; done)
qemu $OPTIONS -net nic,vlan=0,macaddr=$mac,model=rtl8139 -net tap,vlan=0,ifname=$ic,script=no


Первой строчкой мы генерируем mac-адрес для виртуального интерфейса в виртуальной системе. Вторая строчка - непосредственно запуск qemu. Замените $OPTIONS на другие, нужные вам, опции (к примеру, у меня: OPTIONS='-boot d -cdrom install-x86-minimal-2007.0.iso' - загрузится с cd-образа Gentoo, воспринимая его как полноценный cd-диск).

Настройка виртуальной системы

Итак, мы загрузились. Теперь необходимо настроить полученную систему. Общая идея: создать сетефой интерфейс, настроить гейт по умолчанию, настроить DNS.

Реализация (для unix-open_source-like системы - будь то Linux или FreeBSD):

host_ip='192.168.0.2'
virt_ip='192.168.0.3'
broadcast='192.168.0.1'
ifconfig eth0 up $virt_ip netmask 255.255.255.0 broadcast $broadcast
route add default gw $host_ip
echo "nameserver $DNS" > /etc/resolv.conf


Где $DNS - адрес вашего DNS сервера (чтобы узнать его, сделайте "cat /etc/resolv.conf" в реальной системе и внимательно посмотрите на строки, начинающиеся с "nameserver" - это именно ваши сервера DNS).

* Разумеется, учитывайте, что данные команды нужно выполнить от имени пользователя root (посмотрите, как вас зовут: "whoami", и если в вашем паспорте не указано "root" - сделайте "sudo su -" - обычно это работает).

Использование

Пользуйтесь на здоровья. Обе ваши системы - реальная и виртуальная - имеют выход в сеть. Следующими командами можно проверить корректность работы ;-) :


ping 192.168.0.2
ping www.blogger.com


Уничтожение виртуального интерфейса и очистка таблицы firewall'а NAT

После завершения выполнения QEMU сделайте:

su -c 'rmmod tun && iptables -t nat --flush'


При удалении модуля tun уничтожаться все виртуальные интерфейсы, а действие "flush" очистит таблицу firewall'а NAT.

Замечу, что в некоторых руководствах рекомендуют перед всем этим выполнить (на тот случай, если модуль tun выгружать не нужно или выгрузить не возможно):


su -c "tunctl -d $i &> /dev/null"


Примечание (к вопросу о DNS - пункт 8)

Команда:


echo "nameserver $DNS" > /etc/resolv.conf


Довольно неудобна в том случае, если вы используете DHCP для определения $host_ip. К примеру, следуя unix-way, я написал скрипт для поднятия сетевого интерфейса на виртуальном компьютере. Скрипт записан на образ флоппи-дискеты, а образ подключается непосредственно к виртуальной машине. Так вот. Куда удобнее (а для моего скрипта - единственный выход) делать:


echo "nameserver $host_ip" > /etc/resolv.conf


Запросы DNS будут, в таком случае, следовать в реальную систему. В реальной системе можно, конечно, поднять BIND (для домашней сети, кстати, очень удобно - вы сможете иметь доступ ко всем компьютерам с помощью символьных имен), но можно воспользоваться средствами iptables. Просто сделайте в пункте 6 еще и:


iptables -t nat -A PREROUTING -p udp --dport 53 -j DNAT --to-destination $DNS


Т.е. пакеты, пришедшие на порт 53 в формате udp (DNS-запросы), перенаправлять на хост $DNS - являющийся внешним DNS-сервером. Если вы решите написать скрипт для запуска QEMU с поддержкой сети, распарсить /etc/resolv.conf и присвоить DNS ip-адрес одного из серверов DNS не составит труда.

Вся последовательность действий по выводу виртуальной машины в сеть автоматизируется с помощью скрипта. Если вы используете в качестве виртуальной системы unix-like систему - вы сможете автоматизировать настройку сети и в ней - просто напишите скрипт, его поместите на образ флоппи-дискетки - и пользуйтесь!

Комментариев нет: