пятница, 11 апреля 2014 г.

Build switch from linux

Необходимо собрать свитч из стандартного ПК.
На машине имеется 2 встроенные сетевые Реалтэк,
и 4-х портовая плата PCI-X Intel (итого 6 портов).
Задачи свича:
а) Мултикаст роутер.
б) Необходимо иметь возможность дропать определенные категории пакетов на определенных интерфейсах.

1. Собираю минимальную ФС
1.1 Устанавливаю по дефолту Astra-linux-orel-1.9
1.2 Создаю каталог где будет собираться образ будущей системы и перехожу в него:

mkdir -p /root/src
cd /root/src


1.3 Перед сборкой файловой системы, необходимо смэйковать busybox:

mkdir busybox
cd busybox
wget ftp://astra-linux.com/astra/stable/orel/1.9/repository/pool/main/b/busybox/busybox_1.20.0.orig.tar.bz2
tar -xjf busybox_1.20.0.orig.tar.bz2
cd busybox-1.20.0
make menuconfig


##############################################################
General Configuration --->
    Build Options --->
        [*] Build Busybox as a static binary (no shared libs)
##############################################################

# Кроме статической компиляции выбираем нужные опции и мэйкуем

make
mkdir ../../switch_src
cp -a busybox ../../switch_src
cd ../..


1.4 Файловую систему буду собирать при помощи скрипта, поэтому создаю скрипт и делаю его исполняемым:

pwd /root/src
touch buildswitch
chmod +x buildswitch


1.5 Содержимое скрипта:

=========================================================================
#!/bin/bash
set -x


# Директория где будет собираться образ ФС

ROOTFS="/root/src/fs/switchfs"

# Директория где лежат необходимые файлы для сборки ФС (об этом ниже)

SRC="/root/src/switch_src"

mkdir -p $ROOTFS

cd $ROOTFS

rm -rf *


# MINIMAL_INSTALL

mkdir -p bin dev etc etc/init.d lib lib/x86_64-linux-gnu lib64 proc root sbin sys tmp usr/lib usr/lib/x86_64-linux-gnu usr/bin usr/sbin usr/share \
var/empty var/log var/run
chmod 1777 tmp


cd lib/x86_64-linux-gnu
cp /lib/x86_64-linux-gnu/ld-2.13.so .
cp /lib/x86_64-linux-gnu/libc-2.13.so .
cp /lib/x86_64-linux-gnu/libm-2.13.so .
cp /lib/x86_64-linux-gnu/libprocps.so.0.0.1 .
cp /lib/x86_64-linux-gnu/libnss_files-2.13.so .
cp /lib/x86_64-linux-gnu/libgcc_s.so.1 .
ln -s ld-2.13.so ld-linux-x86-64.so.2
ln -s libc-2.13.so libc.so.6
ln -s libm-2.13.so libm.so.6
ln -s libnss_files-2.13.so libnss_files.so.2
ln -s libprocps.so.0.0.1 libprocps.so.0

cd $ROOTFS/lib64
ln -s /lib/x86_64-linux-gnu/ld-2.13.so ld-linux-x86-64.so.2


# FSTAB

cd $ROOTFS
touch etc/fstab
echo "none    /proc    proc    defaults    0 0" > etc/fstab


# INITTAB

touch etc/inittab
echo "::sysinit:/etc/init.d/rcS" > etc/inittab
echo "::once:-/bin/sh" >> etc/inittab
echo "::ctrlaltdel:/sbin/reboot" >> etc/inittab
echo "::shutdown:/bin/umount -a -r" >> etc/inittab
echo "::restart:/sbin/init" >> etc/inittab
echo "tty2::askfirst:-/bin/sh" >> etc/inittab


# RCS

touch etc/init.d/rcS
chmod +x etc/init.d/rcS
cat > etc/init.d/rcS << "EOF"
#!/bin/ash
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mount -o remount,rw /dev/ram0 /
mknod /dev/null c 1 3
mknod /dev/tty c 5 0
mdev -s
mkdir -p /dev/pts
mount -t devpts devpts /dev/pts
syslogd -O /var/log/messages
ifconfig lo 127.0.0.1 up

# Настройка сетевых интерфейсов перед добавлением в бридж
ip a a 0.0.0.0 dev eth0
ip a a 0.0.0.0 dev eth1
ip a a 0.0.0.0 dev eth2
ip a a 0.0.0.0 dev eth3
ip a a 0.0.0.0 dev eth4
ip a a 0.0.0.0 dev eth5

# Добавляю интерфейсы в бридж
brctl addbr br0
brctl addif br0 eth0
brctl addif br0 eth1
brctl addif br0 eth2
brctl addif br0 eth3
brctl addif br0 eth4
brctl addif br0 eth5

# Поднимаю интерфейсы
# На данном этапе возможны проблемы
# Дело в том, что в дефолтной Astra-linux железо инициализирует демон UDEV
# Система собранная мной, работает на основе BUSYBOX, в котором железо инициализирует демон MDEV (посути обрезанный UDEV)
# UDEV и MDEV по разному инициализируют железо
# В результате имена сетевых интерфейсов в дефолтной Astra-linux и в системе на основе BUSYBOX будут различатся
# Один и тот же интерфейс в дефолтной Astra-linux м.б. eth0, а в системе на основе BUSYBOX eth4
# В дефолтной Astra-linux имена сетевых интерфейсов можно изменить в файле /etc/udev/rules.d/70-persistent-net.rules
# В системе на основе BUSYBOX, можно поступить следующим образом (пример, необходимо редактировать в конкретном случае)
ip link set name eth6 dev eth0        # Сначала необходимо освободить имя eth0, поэтому переименовываю его в свободное (незанятое
                                                    # имя) например eth6
ip link set name eth0 dev eth1        # Затем переименовываю eth1 (или другой интерфей которому необходимо назначить имя eth0) в eth0
ip link set dev eth0 up                    # Поднимаю eth0
ip link set name eth1 dev eth2        # Переименовываю eth2 в eth1
ip link set dev eth1 up                    # Поднимаю eth1
ip link set name eth2 dev eth3        # Переименовываю eth3 в eth2
ip link set dev eth2 up                    # Поднимаю eth2
ip link set name eth3 dev eth4        # Переименовываю eth4 в eth3
ip link set dev eth3 up                    # Поднимаю eth3
ip link set name eth4 dev eth5        # Переименовываю eth5 в eth4
ip link set dev eth4 up                    # Поднимаю eth4
ip link set name eth5 dev eth6        # Остался последний интерфейс eth6 (который переименовали вначале eth0 -> eth6),
                                                    # переименовываю eth6 в eth5
ip link set dev eth5 up                    # Поднимаю eth5
# Назначаю IP-address и поднимаю бридж
ip a a 192.168.1.1/24 dev br0
ip link set dev br0 up

# На всякий случай
sleep 1
# Кладу в переменные пиды процессов сетевых карт
pid_eth0=`ps | grep -v grep | grep 'eth0' |awk '{print $1}'` > /dev/null 2>&1
pid_eth1=`ps | grep -v grep | grep 'eth1' |awk '{print $1}'` > /dev/null 2>&1
pid_eth2=`ps | grep -v grep | grep 'eth2' |awk '{print $1}'` > /dev/null 2>&1
pid_eth3=`ps | grep -v grep | grep 'eth3' |awk '{print $1}'` > /dev/null 2>&1
pid_eth4=`ps | grep -v grep | grep 'eth4' |awk '{print $1}'` > /dev/null 2>&1
pid_eth5=`ps | grep -v grep | grep 'eth5' |awk '{print $1}'` > /dev/null 2>&1

# По пидам выставляю сетевым интерфейсам максимальный приоритет ввода\вывода,
# максимальный приоритет доступа к ресурсам процессора,
# и привязываю сетевые интерфейсы к ядрам процессора, что бы исключить миграцию между ядрами (поскольку собирается реал-тайм
# система)
renice -20 -p $pid_eth0 && chrt -f -p 99 $pid_eth0 && taskset -p 1 $pid_eth0 > /dev/null 2>&1
renice -20 -p $pid_eth1 && chrt -f -p 99 $pid_eth1 && taskset -p 2 $pid_eth1 > /dev/null 2>&1
renice -20 -p $pid_eth2 && chrt -f -p 99 $pid_eth2 && taskset -p 3 $pid_eth2 > /dev/null 2>&1
renice -20 -p $pid_eth3 && chrt -f -p 99 $pid_eth3 && taskset -p 4 $pid_eth3 > /dev/null 2>&1
renice -20 -p $pid_eth4 && chrt -f -p 99 $pid_eth4 && taskset -p 1 $pid_eth3 > /dev/null 2>&1
renice -20 -p $pid_eth5 && chrt -f -p 99 $pid_eth5 && taskset -p 2 $pid_eth3 > /dev/null 2>&1

# Дропаю форвард броадкаста на интерфейсе eth1
# Необходимо запретить броадкаст от определенной машины (MAC 08:00:22:03:15:03) и только на определенном интерфейсе (eth1)
# Для этого в систему были добавленны iptables и ebtables (пока обхожусь ebtables)
/sbin/ebtables -A FORWARD -p IPv4 -s 08:00:22:03:15:03 -d FF:FF:FF:FF:FF:FF -o eth1 -j DROP
# Стартую телнет и синхронизирую время
telnetd -l /bin/login
hwclock -s
EOF


# GROUP

touch etc/group
echo "root:x:0:" > etc/group
echo "toor:x:500:" >> etc/group


# GSHADOW

touch etc/gshadow
echo "root:*::" > etc/gshadow
echo "toor:*::" >> etc/gshadow


# PASSWD

touch etc/passwd
echo "root:x:0:0:,,,:/:/bin/ash" > etc/passwd
echo "toor:x:500:500:,,,:/var/empty:" >> etc/passwd


# SHADOW

touch etc/shadow
echo "root::14000:0:99999:7:::" > etc/shadow
echo "toor::14000:0:99999:7:::" >> etc/shadow


# NSSWITCH.CONF

touch etc/nsswitch.conf
echo "passwd: files" > etc/nsswitch.conf
echo "shadow: files" >> etc/nsswitch.conf
echo "group:  files" >> etc/nsswitch.conf
echo "hosts: dns" >> etc/nsswitch.conf


# BUSYBOX.CONF

touch etc/busybox.conf
echo "[SUID]" > etc/busybox.conf
echo "login = ssx root.root" >> etc/busybox.conf


# LOCALTIME

cp -a /etc/localtime etc/

# MTAB

cd etc
ln -s /proc/mounts mtab
cd $ROOTFS


# PROTOCOLS

cp -a /etc/protocols etc/

# ETHERTYPES

cp -a /etc/ethertypes etc/

# IPTABLES

cp -a /sbin/xtables-multi sbin/
cd sbin
ln -s xtables-multi iptables
cd $ROOTFS
cp -a /lib/libip4tc.so.0.0.0 lib/
cp -a /lib/libip6tc.so.0.0.0 lib/
cp -a /lib/libxtables.so.7.0.0 lib/
cd lib
ln -s libip4tc.so.0.0.0 libip4tc.so.0
ln -s libip6tc.so.0.0.0 libip6tc.so.0
ln -s libxtables.so.7.0.0 libxtables.so.7
cd $ROOTFS


# EBTABLES
# Ebtables по дефолту отсутствует в системе, поэтому перед запуском скрипта необходимо выполнить apt-get install ebtables

cp -a /sbin/ebtables sbin/
mkdir lib/ebtables
cp -a /lib/ebtables/* lib/ebtables/


# BUSYBOX
# В каталоге /root/src/switch_src (переменная $SRC) лежит смэйкованный busybox, копирую в каталог bin

cp -a $SRC/busybox bin/
# Инсталирую busybox, удаляю ссылку linuxrc, создаю ссылку init.

chroot . /bin/busybox --install -s
unlink linuxrc
ln -s /bin/busybox init


# # strip

strip -vs bin/*
strip -vs sbin/*
strip -vs usr/sbin/*
strip -vs usr/bin/*
strip -vs lib/x86_64-linux-gnu/*
strip -vs lib64/*
strip -vs usr/lib/*
strip -vs usr/lib/x86_64-linux-gnu/*

=========================================================================

1.6 Пакую образ ФС в initramfs.igz

find . | cpio -H newc -o | gzip -9 > /root/src/switch_src/initramfs.igz

1.7 Собираю ядро

mkdir /root/src/kernel
cd /root/src/kernel


wget ftp://astra-linux.com/astra/stable/orel/1.9/repository/pool/main/l/linux/linux_3.2.0.orig.tar.gz
wget https://www.kernel.org/pub/linux/kernel/projects/rt/3.2/older/patch-3.2-rt10.patch.bz2
tar xvzf linux_3.2.0.orig.tar.gz
bzip2 -d patch-3.2-rt10.patch.bz2
cd linux-3.2
patch -p1 < ../patch-3.2-rt10.patch

cp -a /root/src/switch_src/config .config                                        # Был готовый конфиг
linux64 make menuconfig

# Опишу только необходимые опции данной конфигурации, скопированный выше конфиг содержит все необходимые опции
# минимального ядра

# Добавляю поддержку initramfs

General setup --->
    [*] Initial RAM filesystem and RAM disk (initramfs/initrd) support 
          
    ()    Initramfs source file(s)
    [*]   Support initial ramdisks compressed using gzip
    [ ]   Support initial ramdisks compressed using bzip2
    [ ]   Support initial ramdisks compressed using LZMA
    [ ]   Support initial ramdisks compressed using XZ
    [ ]   Support initial ramdisks compressed using LZO


# Модулей у меня нет поскольку ядро статик   

[ ] Enable loadable module support  ---> 

# Тип процессора

Processor type and features  --->
    Processor family (Generic-x86-64)  ---> 
                           # Добавляю поддержку 64bit процессора
        (X) Generic-x86-64
    Preemption Model (Fully Preemptible Kernel (RT))  --->
     # Полностью вытесняемое ядро (RT-Kernel)
        (X) Fully Preemptible Kernel (RT)
    Timer frequency (1000 HZ)  --->   
                                   # Выставляю таймер на 1000 HZ   
        (X) 1000 HZ
   
# Поддержка сетевых функций

[*] Networking support  --->
    Networking options  --->
        [*] Packet socket
        [*] Unix domain sockets
        [*] TCP/IP networking
            [*]   IP: multicasting
            [*]   IP: kernel level autoconfiguration
                [*]     IP: DHCP support

            [*]   IP: multicast routing                                            # Созданная система должна выполнять роль мультикаст роутера
                [*]     IP: PIM-SM version 1 support
                [*]     IP: PIM-SM version 2 support
            [*]   IP: ARP daemon support
            [*]   IP: TCP syncookie support
        [*] Network packet filtering framework (Netfilter)  --->
            [*]   Advanced netfilter configuration

                [*]     Bridged IP/ARP packets filtering                    # Необходимо дропать определенные пакеты на определенных портах
                                                                                           # поэтому мне необходим фильтр на бридже
                    Core Netfilter Configuration  --->
                        -*- Netfilter NFQUEUE over NFNETLINK interface       
                        -*- Netfilter LOG over NFNETLINK interface
                        [ ] Netfilter connection tracking support
                        -*- Netfilter Xtables support (required for ip_tables)
                            *** Xtables combined modules ***
                        -*-   nfmark target and match support 
                            *** Xtables targets ***

                        [*]   AUDIT target support                                # Поскольку с iptables пришлось работать впервые (предпочитаю BSD и
                                                                                             # PF), а собираемая система была лишь тестовым образцом  
                        [*]   "CLASSIFY" target support                        # я не стал разбираться со значением опций, тупо выбрал все (авось не
                                                                                             # сломается).
                        [*]   IDLETIMER target support                         # Впринципе iptables мне не нужен, добавил на всякий случай, если вдруг
                                                                                             # мне все же захочется каких-то особых извращений,
                        [*]   "MARK" target support                              # что бы не пересобирать ядро снова.
                        [*]   "NFLOG" target support
                        [*]   "NFQUEUE" target Support
                        -*-   "RATEEST" target support
                        [*]   "TEE" - packet cloning to alternate destination
                        [*]   "TCPMSS" target support
                            *** Xtables matches ***
                        [*]   "addrtype" address type match support
                        [*]   "comment" match support
                        [*]   "cpu" match support
                        [*]   "dccp" protocol match support
                        [*]   "devgroup" match support
                        [*]   "dscp" and "tos" match support
                        [*]   "esp" match support
                        [*]   "hashlimit" match support
                        [*]   "hl" hoplimit/TTL match support
                        [*]   "iprange" address range match support
                        [*]   "length" match support
                        [*]   "limit" match support
                        [*]   "mac" address match support
                        [*]   "mark" match support
                        [*]   "multiport" Multiple port match support
                        [*]   "osf" Passive OS fingerprint match
                        [*]   "owner" match support
                        [*]   "physdev" match support
                        [*]   "pkttype" packet type match support
                        [*]   "quota" match support
                        [*]   "rateest" match support
                        [*]   "realm" match support
                        [*]   "recent" match support
                        [*]   "sctp" protocol match support (EXPERIMENTAL)
                        [*]   "statistic" match support
                        [*]   "string" match support
                        [*]   "tcpmss" match support
                        [*]   "time" match support
                        [*]   "u32" match support
                    IP: Netfilter Configuration  --->
                        [*] IP Userspace queueing via NETLINK (OBSOLETE)
                        [*] IP tables support (required for filtering/masq/NAT)
                        [*]   Packet filtering
                        [*] ARP tables support
                        [*]   ARP packet filtering
            [*]   Ethernet Bridge tables (ebtables) support  --->

                --- Ethernet Bridge tables (ebtables) support                    # Здесь аналогичная ситуация как и с iptables, тупо выбрал все
                [*]   ebt: broute table support 
                [*]   ebt: filter table support
                [*]   ebt: nat table support
                [*]   ebt: 802.3 filter support
                [*]   ebt: among filter support
                [*]   ebt: ARP filter support
                [*]   ebt: IP filter support
                [*]   ebt: limit match support
                [*]   ebt: mark filter support
                [*]   ebt: packet type filter support
                [*]   ebt: STP filter support
                [*]   ebt: 802.1Q VLAN filter support
                [*]   ebt: arp reply target support
                [*]   ebt: dnat target support
                [*]   ebt: mark target support
                [*]   ebt: redirect target support
                [*]   ebt: snat target support
                [*]   ebt: log support
                [*]   ebt: ulog support (OBSOLETE)
                [*]   ebt: nflog support
        [*] 802.1d Ethernet Bridging
        [*]   IGMP/MLD snooping   
        -*- DNS Resolver support   
Device Drivers  --->
    [*] Network device support  --->

        [*]   Ethernet driver support  --->                                        # На машине имеется 2 встроенные сетевые Realtek 8169
            [*]   Intel devices                                                          # и четырех портовая плата Intel в PCI-X
            [*]     Intel(R) PRO/1000 Gigabit Ethernet support           # Выбираю необходимые драйвера
            [*]     Intel(R) PRO/1000 PCI-Express Gigabit Ethernet support
            [*]   Realtek devices
            [*]     Realtek 8169 gigabit ethernet support

    [*] Real Time Clock  --->                                                       # Необходимо для синхронизации времени
        --- Real Time Clock
        [*]   Set system time from RTC on startup and resume (NEW)
        (rtc0)  RTC used to set the system time (NEW)
            *** RTC interfaces ***
        [*]   /sys/class/rtc/rtcN (sysfs) (NEW)
        [*]   /proc/driver/rtc (procfs for rtc0) (NEW)
        [*]   /dev/rtcN (character devices) (NEW)
            *** SPI RTC drivers ***
            *** Platform RTC drivers ***
        [*]   PC-style 'CMOS' (NEW)

       
# Остальные опции выбираем по необходимости       
# Мэйкую ядро
          
linux64 make -j3

# Копирую собранное ядро в каталог /root/src/switch_src

cp arch/x86/boot/bzimage /root/src/switch_src/vmlinuz-bridge

1.8 Система практически готова, осталось создать раздел, положить туда образ ФС initramfs.igz и ядро vmlinuz-bridge, и установить загрузчик.

# Предположим, что в машине имеется еще один диск

cfdisk /dev/sdb
/dev/sdb1    1024MB
                                                                # Создаем раздел 1Gb

# Форматируем в ext2

mke2fs /dev/sdb1
tune2fs -c 0 -i 0 /dev/sdb1


# Монтируем в /mnt

mount /dev/sdb1 /mnt

# Копируем ядро и образ ФС системы

cp -a /root/src/switch_src/vmlinuz-bridge /mnt
cp -a /root/src/switch_src/initramfs.igz /mnt


# Гружусь с Gentoo LIVE CD
# Монтирую sdb1 в /mnt

mount /dev/sdb1 /mnt

# В /mnt создаю каталог grub

mkdir /mnt/grub

# Копирую в него необходимые грабовские файлы

cp /boot/grub/stage? /boot/grub/e2fs_stage1_5 /mnt/grub

# Отмонтирую раздел

umount /mnt

# Устанавливаю загрузчик

grub
grub> device (hd0) /dev/sdb
grub> root (hd0,0)
grub> setup (hd0)
grub> quit


# Создаю файл menu.lst
# Для этого снова монтирую раздел

mount /dev/sdb1 /mnt
touch /mnt/grub/menu.lst
echo "timeout 0" > /mnt/grub/menu.lst
echo "default 0" >> /mnt/grub/menu.lst
echo "fallback 2" >> /mnt/grub/menu.lst
echo "title Bridge" >> /mnt/grub/menu.lst
echo "kernel /vmlinuz-bridge initrd=/initramfs.igz quiet ramdisk_size=32768" >> /mnt/grub/menu.lst
echo "initrd /initramfs.igz" >> /mnt/grub/menu.lst


# Вот что должно получится

cat /mnt/target/grub/menu.lst

timeout 0
default 0
fallback 2
title Bridge
kernel /vmlinuz-bridge initrd=/initramfs.igz quiet ramdisk_size=32768
initrd /initramfs.igz


# Отмонтирую раздел

umount /mnt/target

# Загружаюсь в новой системе, проверяю работу.