Compare commits

...

32 Commits

Author SHA1 Message Date
Szymon Karpiński dcbf9a9a0d Downloading syslinux files on build 7 years ago
Szymon Karpiński 4d5f3f1ba8 scripts/ removed 7 years ago
Szymon Karpiński 745a5ebf0a Dockerfile comments 7 years ago
Szymon Karpiński 4f85d4bf1b Minor readme fixes 7 years ago
Szymon Karpiński 0245fac669 Readme improved 7 years ago
Szymon Karpiński b39d43aaf8 Basic readme 7 years ago
Szymon Karpiński 8ba060b9f0 dockerfile fix 7 years ago
Szymon Karpiński 497dbc49de moving files to src/tftpboot 7 years ago
Szymon Karpiński 495fed5c16 removed global makefile 7 years ago
Szymon Karpiński 3155b8a464 Linux built into the server 7 years ago
Szymon Karpiński 059fb16ac9 main makefile modified 7 years ago
Szymon Karpiński 8d4ad10507 removing syslinux 7 years ago
Szymon Karpiński e670eeacb6 moving scripts to scripts/ 7 years ago
Szymon Karpiński 13b5d15c51 storing some files/ 7 years ago
Szymon Karpiński 2a68ab6c2d dhcp & tftp/http servers merged 7 years ago
Szymon Karpiński 57c2a0d373 moved http to 8014 7 years ago
Szymon Karpiński 8f49275872 makefiles tested on fresh system 7 years ago
Szymon Karpiński 4c26a41a3c menu rewritten 7 years ago
Szymon Karpiński f2df1ca2b8 sending works 7 years ago
Szymon Karpiński 248c1f033b sending works 7 years ago
Szymon Karpiński 739ce24c47 Simple menu 7 years ago
Szymon Karpiński cc13b249d5 tmpfs 7 years ago
Szymon Karpiński 62841c4545 minor fixes to global makefile 7 years ago
Szymon Karpiński 02ae9feb62 Fixed autologin 7 years ago
Szymon Karpiński 3e4a106048 Auto copy from src/ 7 years ago
Szymon Karpiński 3bb7cdde07 root autologin 7 years ago
Szymon Karpiński 5ffaf42e5a downloading squashfs over http for faster boot 7 years ago
Szymon Karpiński 514ad3bf8b Bootable! 7 years ago
Szymon Karpiński 1fd6fb1d98 basic linux image 7 years ago
Szymon Karpiński 03d8c8df76 dhcp works 7 years ago
Szymon Karpiński 62b72a3ffb tftp working 7 years ago
Szymon Karpiński 5fd38ca5f0 Basic TFTP server container 7 years ago
  1. 4
      .gitignore
  2. 45
      Dockerfile
  3. 79
      Readme.md
  4. 8
      dhcp/Dockerfile
  5. 41
      linux/Makefile
  6. 18
      linux/Readme.md
  7. 1
      linux/src/etc/fstab
  8. 1
      linux/src/etc/initramfs-tools/modules
  9. 8
      linux/src/etc/initramfs-tools/scripts/local-top/download.sh
  10. 2
      linux/src/etc/systemd/logind.conf
  11. 58
      linux/src/lib/systemd/system/getty@.service
  12. 41
      linux/src/scripts/functions.sh
  13. 31
      linux/src/scripts/menu.sh
  14. 3
      src/dhcpd.conf
  15. 6
      src/run.sh
  16. 17
      src/supervisor.conf
  17. 7
      src/tftpboot/pxelinux.cfg/default

4
.gitignore vendored

@ -0,0 +1,4 @@
linux/build/
files/initrd.img
files/vmlinuz
files/root.squashfs

@ -0,0 +1,45 @@
FROM debian:buster
RUN apt update
RUN apt install -y make debootstrap supervisor isc-dhcp-server tftpd-hpa busybox squashfs-tools
# Downloads base Debian 10 to /linux/build/cache. The Makefile in linux/ would
# download base debian system to linux/build/cache itself, but to speed up
# rebuilding this Docker container the download is run separately to avoid
# repeating it in future builds.
ADD linux /linux
RUN mkdir -p linux/build && debootstrap buster linux/build/cache
# Copies src/tftpboot directory to /tftpboot
ADD src/tftpboot /tftpboot
# Downloads Syslinux and moves ldlinux.c32 and pxelinux.0 files to /tftpboot
RUN wget https://mirrors.edge.kernel.org/pub/linux/utils/boot/syslinux/syslinux-6.03.tar.gz && \
tar -xzvf syslinux-6.03.tar.gz && \
cp syslinux-6.03/bios/core/pxelinux.0 /tftpboot/pxelinux.0 && \
cp syslinux-6.03/bios/com32/elflink/ldlinux/ldlinux.c32 /tftpboot/ldlinux.c32
# Builds Linux with its Makefile
RUN cd /linux && make
# Creates and populates /tftpboot directory. Files stored there will be served
# by TFTP and HTTP (on port 8014).
RUN cp /linux/build/rootfs/initrd.img /tftpboot/initrd.img && \
cp /linux/build/rootfs/vmlinuz /tftpboot/vmlinuz && \
mksquashfs /linux/build/rootfs /tftpboot/root.squashfs
# Supervisor's config
COPY src/supervisor.conf /supervisor.conf
# DHCP server config
RUN mkdir -p /var/lib/dhcp && touch /var/lib/dhcp/dhcpd.leases
COPY src/dhcpd.conf /etc/dhcp/dhcpd.conf
# The run.sh script setups networking and starts supervisor.
COPY src/run.sh /run.sh
RUN chmod +x /run.sh
# Interface on which the server will be listening. Set with `-e INTERFACE=eth1`
ENV INTERFACE=eth0
CMD ["/run.sh"]

@ -0,0 +1,79 @@
## Overview
`hugo/images` is a portable, self contained system for distributing
disk images.
It allows to boot connected computers over the network and run a image distribution software on them.
## Usage
### Network setup
This system is meant to be used in physically separated network, with all the computers (including the server) connected to a switch.
### Building
To build, just build the docker container from the `Dockerfile`, for example:
```
docker build . -t hugo/images
```
When run for the first time, the build might take some time because basic Debian image has to be downloaded. On subsequent builds the cache will be used making the build take much less time.
### Running
This container has some requirements to work properly:
- `INTERFACE` environment variable should be set to an interface on which you want the server to operate. You can do this by appending `-e INETRFACE=whatever` to your `docker run` command.
- The server has to be run in privileged mode, so `--privileged` flag has to be added to the command.
- No network isolation of any kind should be enabled. You can connect the container directly to host's interface with `--net host` flag.
An example run command might look like this:
```
docker run -e INETRFACE=eth42 --privileged --net host hugo/images
```
After starting the server, all PCs connected to the network, when in network boot mode, should boot specialised Linux for cloning and present the user with a menu.
## Technical details
The container runs three services: DHCP server, TFTP server and HTTP server (on port 8014, to avoid collisions with HTTP server that can be already running on host system). DHCP server is used to assign IP addresses and point to PXE binary which will continue the boot process, TFTP server is used, as specified in PXE standard, to send basic files needed to boot, and HTTP, as it is much faster than TFTP, is used to transfer whole root filesystem.
### Boot process
The boot process of a computer connected to the server consists of the following steps:
1. The computer searches for DHCP server and asks for an IP address. The server responds (as configured in `src/dhcpd.conf`) with an IP address and the filename of PXE binary.
2. The PXE binary is downloaded over TFTP. When run, it searches (by trying many names, including `pxelinux.cfg/default`) for PXE config file and downloads it over TFTP.
3. This config file (`src/pxelinux.cfg/default`) contains filenames of the linux kernel and initial ramdisk, which are downloaded over TFTP.
4. A network is configured in initrd and full filesystem (as squashfs) is downloaded over HTTP (port 8014) and mounted read-only as `/dev/loop0`. See `linux/src/initramfs-tools/scripts/local-top/download.sh` for more details.
5. As specified in `linux/src/etc/fstab`, a `tmpfs` is mounted in `/tmp`.
6. `root` is automatically logged in and it's default shell, the image distribution software (see `linux/scripts`), is started.
### Linux
The Linux system being server is based on minimal Debian 10 Buster and boots to a menu allowing to send/receive:
1. MBR of `/dev/sda` (raw copy of first 512 bytes, made by `dd`)
2. Partition table (in `sfdisk` format)
3. Image of `/dev/sda1` partition (in `partimage` format)
Both sending and receiving is done with UDP broadcast with `udpsender`/`udpreceiver`. Any custom action can be performed with root shell. See `linux/scripts` for more details.
### Transferring images to/from the server
You can use `udpreceiver`/`udpsender` to receive or send data to/from your server. For example:
```
udp-receiver --interface eth0 > save_it_here
```
```
udp-sender --interface eth0 < file_to_send
```

@ -1,8 +0,0 @@
FROM debian:buster
RUN apt update && apt install -y isc-dhcp-server
RUN mkdir -p /var/lib/dhcp && touch /var/lib/dhcp/dhcpd.leases
COPY dhcpd.conf /etc/dhcp/dhcpd.conf
COPY run.sh /run.sh
RUN chmod +x /run.sh
ENV INTERFACE=eth0
CMD ["/run.sh"]

@ -0,0 +1,41 @@
CHROOT_CMD := chroot build/rootfs /bin/bash -c
FILES = $(shell find src/ -type f -print | sed -e 's|^src/|build/rootfs/|')
FILES_SRC = $(shell find src/ -type f -print)
all: $(FILES) menu images build/rootfs/initrd.img
clean:
rm -rf build/rootfs
menu: build/rootfs | build
$(CHROOT_CMD) "apt install dialog"
$(CHROOT_CMD) "chmod +x /scripts/menu.sh"
$(CHROOT_CMD) "usermod -s /scripts/menu.sh root"
images: build/rootfs | build
$(CHROOT_CMD) "apt install -y udpcast"
$(CHROOT_CMD) "apt install -y partclone"
$(CHROOT_CMD) "apt install -y lzop strace"
$(CHROOT_CMD) "touch /etc/mtab"
build/rootfs/initrd.img: build/rootfs $(FILES) | build
chmod +x build/rootfs/etc/initramfs-tools/scripts/local-top/download.sh
$(CHROOT_CMD) "apt update && apt install -y linux-image-4.19.0-*-amd64"
$(CHROOT_CMD) "update-initramfs -c -kall"
$(FILES): $(FILES_SRC) build/rootfs | build
mkdir -p $(@D)
cp $(shell echo $@ | sed -e 's|^build/rootfs/|src/|') $@
build/rootfs: build/cache | build
rm -rf build/rootfs
cp -r build/cache build/rootfs
rm -rf $(FILES)
build/cache: | build
rm -rf build/cache || true
debootstrap buster build/cache
build:
mkdir -p build

@ -0,0 +1,18 @@
# Linux for cloning
## About
`images/linux` is Debian 10 system adapted for network booting and sending/receiving disk images via UDP. It is designed to work together with `images/server`.
On boot, full system image will be downloaded, mounted read only and will become new root (see `src/etc/initramfs-tools`). User will be presented with menu allowing sending/receiving images and root shell access (see `src/scripts`). Whole environment will be read-only, except `/tmp` where writeable `tmpfs` will be mounted.
## Installation
To build just run:
```
sudo make
```
This will download base system to `build/cache`, copy it to `build/rootfs` and continue build there. After successful completion of this command, a fully functional linux root filesystem will be present in `build/rootfs`.
`debootstrap` is required to download base Linux system. When more advanced (encrypted home etc.) partition setup is used, one might need to remount the partition on which the build is taking place with `exec` and `dev` before running `make`:
```
sudo mount -i -o remount,exec,dev /home/whatever
```

@ -0,0 +1 @@
tmpfs /tmp tmpfs defaults,noatime,nosuid,nodev,noexec,mode=1777,size=256M 0 0

@ -0,0 +1,8 @@
#!/bin/sh
. /scripts/functions
configure_networking
wget http://192.168.14.2:8014/root.squashfs
mkdir /mnt
modprobe loop
losetup /dev/loop0
losetup -r /dev/loop0 /root.squashfs

@ -0,0 +1,2 @@
[Login]
NAutoVTs=1

@ -0,0 +1,58 @@
# SPDX-License-Identifier: LGPL-2.1+
#
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
[Unit]
Description=Getty on %I
Documentation=man:agetty(8) man:systemd-getty-generator(8)
Documentation=http://0pointer.de/blog/projects/serial-console.html
After=systemd-user-sessions.service plymouth-quit-wait.service getty-pre.target
After=rc-local.service
# If additional gettys are spawned during boot then we should make
# sure that this is synchronized before getty.target, even though
# getty.target didn't actually pull it in.
Before=getty.target
IgnoreOnIsolate=yes
# IgnoreOnIsolate causes issues with sulogin, if someone isolates
# rescue.target or starts rescue.service from multi-user.target or
# graphical.target.
Conflicts=rescue.service
Before=rescue.service
# On systems without virtual consoles, don't start any getty. Note
# that serial gettys are covered by serial-getty@.service, not this
# unit.
ConditionPathExists=/dev/tty0
[Service]
# the VT is cleared by TTYVTDisallocate
# The '-o' option value tells agetty to replace 'login' arguments with an
# option to preserve environment (-p), followed by '--' for safety, and then
# the entered username.
ExecStart=-/sbin/agetty --autologin root --noclear %I 38400 linux
Type=idle
Restart=always
RestartSec=0
UtmpIdentifier=%I
TTYPath=/dev/%I
TTYReset=yes
TTYVHangup=yes
TTYVTDisallocate=yes
KillMode=process
IgnoreSIGPIPE=no
SendSIGHUP=yes
# Unset locale for the console getty since the console has problems
# displaying some internationalized messages.
UnsetEnvironment=LANG LANGUAGE LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT LC_IDENTIFICATION
[Install]
WantedBy=getty.target
DefaultInstance=tty1

@ -0,0 +1,41 @@
#!/bin/bash
INTERFACE=eth0
RECEIVER="udp-receiver --interface $INTERFACE"
SENDER="udp-sender --interface $INTERFACE"
pause () {
echo
read -p "Press [Enter] to continue..."
clear
}
shell () {
clear
bash
}
recv_dd () {
$RECEIVER | dd of=$1 bs=512 count=1
}
recv_sfd () {
$RECEIVER | sfdisk $1
}
recv_pc () {
$RECEIVER | lzop -d | partclone.extfs -r -s - -o $1 --logfile /tmp/partclone.log
}
send_dd () {
dd if=$1 bs=512 count=1 | $SENDER
}
send_pc () {
partclone.extfs -s $1 -c --logfile /tmp/partclone.log 2>/dev/null | lzop | $SENDER
}
send_sfd () {
sfdisk -d $1 | $SENDER
}

@ -0,0 +1,31 @@
#!/bin/bash
dmesg -n 1
source $( dirname "${BASH_SOURCE[0]}" )/functions.sh
dialog --menu "Welcome to hugo/images!" 20 80 10 \
1 "Receive image for /dev/sda1 (partclone+lzop)" \
2 "Receive partition table for /dev/sda (sfdisk)" \
3 "Receive MBR for /dev/sda (dd)" \
4 "Send /dev/sda1 image (partclone+lzop)" \
5 "Send /dev/sda partition table (sfdisk)" \
6 "Send /dev/sda MBR (dd)" \
7 "Run root shell" \
8 "Reboot" \
9 "Poweroff" \
2>/tmp/menu
if [ "$?" != "0" ]; then CHOICE=7; else CHOICE=$(cat /tmp/menu); fi
case $CHOICE in
1) recv_pc /dev/sda1; pause ;;
2) recv_sfd /dev/sda; pause ;;
3) recv_dd /dev/sda; pause ;;
4) send_pc /dev/sda1; pause ;;
5) send_sfd /dev/sda; pause ;;
6) send_dd /dev/sda; pause ;;
7) shell ;;
8) reboot ;;
9) poweroff ;;
esac

@ -4,5 +4,6 @@ default-lease-time 600;
max-lease-time 7200; max-lease-time 7200;
subnet 192.168.14.0 netmask 255.255.255.0 { subnet 192.168.14.0 netmask 255.255.255.0 {
range 192.168.14.10 192.168.14.250; range 192.168.14.10 192.168.14.250;
filename "pxelinux.0";
} }

@ -1,6 +1,10 @@
#!/bin/bash #!/bin/bash
set -e set -e
# Inteface setup
ip addr flush dev $INTERFACE ip addr flush dev $INTERFACE
ip addr add 192.168.14.2/24 dev $INTERFACE ip addr add 192.168.14.2/24 dev $INTERFACE
ip link set dev $INTERFACE up ip link set dev $INTERFACE up
dhcpd -d --no-pid $INTERFACE
# Supervisor
supervisord -n -c /supervisor.conf

@ -0,0 +1,17 @@
[supervisord]
loglevel = DEBUG
[program:dhcp]
command = dhcpd -d --no-pid %(ENV_INTERFACE)s
autostart = true
autorestart = true
[program:tftp]
command = in.tftpd -L -s /tftpboot
autostart = true
autorestart = true
[program:http]
command = busybox httpd -f -p 8014 -h /tftpboot
autostart = true
autorestart = true

@ -0,0 +1,7 @@
DEFAULT linux
LABEL linux
kernel vmlinuz
append initrd=initrd.img root=/dev/loop0 net.ifnames=0 biosdevname=0
PROMPT 0
TIIMEOUT 0
Loading…
Cancel
Save