#!/bin/sh # # Copyright 2011, 2016, 2017, 2019, 2023 Eric Hameleers, Eindhoven, NL # Copyright 2011 Patrick Volkerding, Sebeka, Minnesota USA # All rights reserved. # # Redistribution and use of this script, with or without modification, is # permitted provided that the following conditions are met: # # 1. Redistributions of this script must retain the above copyright # notice, this list of conditions and the following disclaimer. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO # EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; # OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # Code used from SeTpxe and SeTnet scripts, part of the Slackware installer. # --------------------------------------------------------------------------- # PXEserver works as follows: # - It requires a wired network; wireless PXE boot is impossible. # - The pxeserver script tries to find a wired interface; you can pass an # explicit interfacename as parameter to the script (optional). # - If multiple wired interfaces are detected, a dialog asks the user to # select the right one. # - A check is done for DHCP configuration of this wired interface; # * If DHCP configuration is found then pxeserver will not start its own # DHCP server and instead will rely on your LAN's DHCP server. # * If no DHCP config is found, the script will ask permission to start # its own internal DHCP server. # Additionally the user will be prompted to configure an IP address for the # network interface and IP range properties for the internal DHCP server. # - The script will then start the PXE server, comprising of: # * dnsmasq providing DNS, DHCP and BOOTP; # * NFS and RPC daemons; # - The script will detect if you have an outside network connection on # another interface and will enable IP forwarding if needed, so that the # PXE clients will also have network access. # - Optionally, the script can hide its PXE clients behind a NAT router # in case external network is not accessible via normal routing. # - The Live OS booted via pxelinux is configured with additional boot # parameters: # * nfsroot=${LOCAL_IPADDR}:/mnt/livemedia # * luksvol= # * nop # * hostname=@DISTRO@ # * tz=$(cat /etc/timezone) # * locale=${SYSLANG:-"en_US.UTF-8"} # * kbd=${KBD:-"us"} # Which shows that the configuration of the Live OS where the PXE server # runs is largely determining the configuration of the PXE clients. # - Note that when networkbooting, the hostname of the Live OS will be # suffixed with the machine's MAC address to make every network-booted # Live OS unique. # # Initialization: # DEBUG=${DEBUG:-0} DIALOG=dialog # UEFI prefix: UEFIPREFIX="/EFI/BOOT" # Number of PXE clients we want to serve with our own DHCP server: DEF_DHCP_RANGE=${DEF_DHCP_RANGE:-10} # Optional argument to the script is the name of the interface on which # the PXE server should run: INTERFACE="$1" # This variable will be used to determine if the network default gateway # is reached through a second NIC in the computer, or not. GLOBAL_GW_INT="" # In the above case, the global and local gateways will not be equal. GLOBAL_GATEWAY="" LOCAL_GATEWAY="" # Defining more global variables ahead of time: LOCAL_IPADDR="" LOCAL_NETMASK="" LOCAL_NETWORK="" # The script optionally configures a NAT gateway: ENABLE_NAT="no" # The Slackware setup depends on english language settings because it # parses program output like that of "fdisk -l". So, we need to override # the Live user's local language settings here: SYSLANG=$LANG export LANG=C export LC_ALL=C # Warn the user if the Live Media is inaccessible (however unlikely): if [ ! -d /mnt/livemedia/@LIVEMAIN@/system ]; then if [ $DEBUG -ne 0 ]; then read -p "Press ENTER to continue: " JUNK ; fi $DIALOG --title "LIVE MEDIA NOT ACCESSIBLE" --msgbox "\ \n\ Before you can install software, complete the following tasks:\n\ \n\ 1. Mount your Live media partition on /mnt/livemedia." 16 68 exit 1 fi TMP=/var/log/setup/tmp if [ ! -d $TMP ]; then mkdir -p $TMP fi rm -f $TMP/SeT* $TMP/pxe* echo "on" > $TMP/SeTcolor # turn on color menus PATH="$PATH:/usr/share/@LIVEMAIN@" export PATH; export COLOR=on # Add some eye candy for BIOS PXE clients: if [ -d /mnt/livemedia/boot/syslinux ]; then PXETXTSRC=/mnt/livemedia/boot/syslinux elif [ -d /mnt/livemedia/boot/extlinux ]; then PXETXTSRC=/mnt/livemedia/boot/extlinux else PXETXTSRC="" fi if [ -n "$PXETXTSRC" ]; then # All the files that are needed for the BIOS PXE boot menu: for SFILE in f2.txt f3.txt f4.txt message.txt swlogov.png ter-i16v.psf vesamenu.c32 do ln -sf ${PXETXTSRC}/${SFILE} /var/lib/tftpboot/ done fi # For UEFI computers: if [ ! -f /mnt/livemedia${UEFIPREFIX}/SLACKWARELIVE ]; then # We boot from a USB stick created with isu2usb.sh: if ! mount |grep -q 'on /boot/efi' ; then # USB EFI partition is not yet mounted, let's find where it is: LIVEPART="$(df -P /mnt/livemedia/ |tail -n1 |cut -d' ' -f1)" USBDEV="/dev/$(lsblk -no pkname ${LIVEPART=})" EFIPART="$(blkid -t PARTLABEL="EFI System Partition" ${USBDEV=}* |cut -d: -f1)" mkdir -p /boot/efi mount -t vfat -o defaults ${EFIPART} /boot/efi fi UEFI_TFTP="/boot/efi" else UEFI_TFTP="/mnt/livemedia" fi # Allow the boot files to be served by tftp: mkdir -p /var/lib/tftpboot${UEFIPREFIX} ln -sf ${UEFI_TFTP}${UEFIPREFIX}/SLACKWARELIVE /var/lib/tftpboot${UEFIPREFIX}/ ln -sf ${UEFI_TFTP}${UEFIPREFIX}/bootx64.efi /var/lib/tftpboot${UEFIPREFIX}/ ln -sf ${UEFI_TFTP}${UEFIPREFIX}/theme /var/lib/tftpboot${UEFIPREFIX}/ # # Function definitions: # # Function to convert the netmask from CIDR format to dot notation. cidr_cvt() { # Number of args to shift, 255..255, first non-255 byte, zeroes set -- $(( 5 - ($1 / 8) )) 255 255 255 255 $(( (255 << (8 - ($1 % 8))) & 255 )) 0 0 0 [ $1 -gt 1 ] && shift $1 || shift echo ${1-0}.${2-0}.${3-0}.${4-0} } # Function to convert the netmask from dot notation to CIDR format. mask_cvt () { # Assumes there's no "255." after a non-255 byte in the mask local x=${1##*255.} set -- 0^^^128^192^224^240^248^252^254^ $(( (${#1} - ${#x})*2 )) ${x%%.*} x=${1%%$3*} echo $(( $2 + (${#x}/4) )) } # IP Address to integer conversion: ip_to_int() { IFS=. set -f set -- $1 echo $(($1 << 24 | $2 << 16 | $3 << 8 | $4)) } # Integer to IP Address conversion: int_to_ip() { echo $(($1>>24)).$(($1>>16&0xff)).$(($1>>8&0xff)).$(($1&0xff)) } # Find out whether the interface is managed by DHCP: get_dhcpcd_pid() { # Find the location of the PID file of dhcpcd: MYDEV="$1" if [ -s /run/dhcpcd/dhcpcd-${MYDEV}.pid ]; then echo "/run/dhcpcd/dhcpcd-${MYDEV}.pid" elif [ -s /run/dhcpcd/dhcpcd-${MYDEV}-4.pid ]; then echo "/run/dhcpcd/dhcpcd-${MYDEV}-4.pid" elif [ -s /run/dhcpcd-${MYDEV}.pid ]; then echo "/run/dhcpcd-${MYDEV}.pid" elif [ -s /run/dhcpcd-${MYDEV}-4.pid ]; then echo "/run/dhcpcd-${MYDEV}-4.pid" elif [ -s /run/${MYDEV}.pid ]; then echo "/run/${MYDEV}.pid" else echo UNKNOWNLOC fi } # Find out whether the interface is managed by DHCP: get_nm_internal_lease() { # Find the lease of NetworkManager internal dhcp client: MYDEV="$1" if [ -s /var/lib/NetworkManager/intern*-${MYDEV}.lease ]; then # NM is indeed managing this interface: echo "$(ls --indicator-style=none /var/lib/NetworkManager/intern*-${MYDEV}.lease)" else echo UNKNOWNLOC fi } # The network interface IP configuration routine. # Will be called if the interface was not configured by DHCP. # It ends with a configured network interface: devconfig() { # Function accepts a parameter; if not given, use the global INTERFACE: MYIF=${1:-"$INTERFACE"} # Determine a LAN range we are going to be using for the internal DHCP # range that does not conflict with existing IP configuration: if ! ip -f inet -o addr show |grep -v " lo " |grep -qw 192.168 ; then MYIP="192.168.10.10" elif ! ip -f inet -o addr show |grep -v " lo " |grep -qw 172.16 ; then MYIP="172.16.10.10" else MYIP="10.16.10.10" fi # Main loop IP configuration: while [ 0 ]; do cat << EOF > $TMP/tempmsg You will need to enter the IP address you wish to assign to interface ${MYIF}. Example: ${MYIP} What is your IP address? EOF if [ "x$LOCAL_IPADDR" = "x" ]; then # assign default LOCAL_IPADDR=${MYIP} fi if [ $DEBUG -ne 0 ]; then read -p "Press ENTER to continue: " JUNK ; fi $DIALOG --title "ASSIGN IP ADDRESS" --inputbox "$(cat $TMP/tempmsg)" 12 \ 65 $LOCAL_IPADDR 2> $TMP/local if [ ! $? = 0 ]; then rm -f $TMP/tempmsg $TMP/local return fi LOCAL_IPADDR="$(cat $TMP/local)" rm -f $TMP/local clear cat << EOF > $TMP/tempmsg Now we need to know your netmask. Typically this will be 255.255.255.0 but this can be different depending on your local setup. What is your netmask? EOF if [ "x$LOCAL_NETMASK" = "x" ]; then # assign default LOCAL_NETMASK=${NETMASK:-255.255.255.0} fi if [ $DEBUG -ne 0 ]; then read -p "Press ENTER to continue: " JUNK ; fi $DIALOG --title "ASSIGN NETMASK" --inputbox "$(cat $TMP/tempmsg)" 14 \ 65 $LOCAL_NETMASK 2> $TMP/mask if [ ! $? = 0 ]; then rm -f $TMP/tempmsg $TMP/mask return fi clear LOCAL_NETMASK="$(cat $TMP/mask)" rm $TMP/mask # GLOBAL_GATEWAY was determined right before calling this function: if [ "x$GLOBAL_GATEWAY" = "x" ]; then if [ $DEBUG -ne 0 ]; then read -p "Press ENTER to continue: " JUNK ; fi $DIALOG --yesno "Do you have a gateway?" 5 30 HAVE_GATEWAY=$? clear if [ $HAVE_GATEWAY -eq 0 ]; then LOCAL_GATEWAY="$(echo $LOCAL_IPADDR | cut -f1-3 -d '.')." if [ $DEBUG -ne 0 ]; then read -p "Press ENTER to continue: " JUNK ; fi $DIALOG --title "ASSIGN GATEWAY ADDRESS" --inputbox \ "\nWhat is the IP address for your gateway?" 9 65 \ $LOCAL_GATEWAY 2> $TMP/gw if [ ! $? = 0 ]; then rm -f $TMP/tempmsg $TMP/gw LOCAL_GATEWAY="" else LOCAL_GATEWAY="$(cat $TMP/gw)" rm -f $TMP/gw fi fi unset HAVE_GATEWAY clear elif [ "$GLOBAL_GW_INT" = "$MYIF" ]; then LOCAL_GATEWAY=$GLOBAL_GATEWAY fi cat << EOF > $TMP/tempmsg This is the proposed network configuration for $MYIF - If this is OK, then select 'Yes'. If this is not OK and you want to configure again, select 'No'. * IP Address: $LOCAL_IPADDR * Netmask: $LOCAL_NETMASK * Gateway: ${LOCAL_GATEWAY:-"$GLOBAL_GATEWAY (via $GLOBAL_GW_INT)"} EOF if [ $DEBUG -ne 0 ]; then read -p "Press ENTER to continue: " JUNK ; fi $DIALOG --no-collapse --title "NETWORK CONFIGURATION" \ --yesno "$(cat $TMP/tempmsg)" 14 68 if [ $? -eq 1 ]; then continue # New round of questions fi #echo "Configuring ethernet card..." if [ $DEBUG -ne 0 ]; then read -p "Press ENTER to continue: " JUNK ; fi $DIALOG --title "INITIALIZING NETWORK" --infobox \ "\nConfiguring your network interface $MYIF ..." 5 56 # We don't need this anymore: dhcpcd -k $MYIF 1>/dev/null 2>&1 rm -f /run/dhcpcd/dhcpcd-${MYIF}.pid 2>/dev/null rm -f /run/dhcpcd-${MYIF}.pid 2>/dev/null rm -f /run/${MYIF}.pid 2>/dev/null # Broadcast and network are derived from IP and netmask: LOCAL_BROADCAST="$(ipmask $LOCAL_NETMASK $LOCAL_IPADDR | cut -f 1 -d ' ')" LOCAL_NETWORK="$(ipmask $LOCAL_NETMASK $LOCAL_IPADDR | cut -f 2 -d ' ')" if [ -x /etc/rc.d/rc.networkmanager 2>/dev/null ]; then # Use nmcli to reconfigure NetworkManager: nmcli con add save no con-name pxe-${MYIF} ifname ${MYIF} type ethernet nmcli con mod pxe-${MYIF} ipv4.addresses ${LOCAL_IPADDR}/$(mask_cvt ${LOCAL_NETMASK}) ipv4.method manual connection.autoconnect no if [ "x$GLOBAL_GATEWAY" = "x" -a "x$LOCAL_GATEWAY" != "x" ]; then nmcli con mod pxe-${MYIF} ipv4.gateway $LOCAL_GATEWAY fi nmcli con up pxe-${MYIF} if [ $DEBUG -ne 0 ]; then read -p "Press ENTER to continue: " JUNK ; fi else # Use ifconfig and route commands: ifconfig $MYIF $LOCAL_IPADDR netmask $LOCAL_NETMASK broadcast $LOCAL_BROADCAST if [ "x$GLOBAL_GATEWAY" = "x" -a "x$LOCAL_GATEWAY" != "x" ]; then #echo "Configuring your gateway..." route add default gw $LOCAL_GATEWAY metric 1 fi fi echo $LOCAL_IPADDR > $TMP/SeTIP echo $LOCAL_NETMASK > $TMP/SeTnetmask echo $LOCAL_GATEWAY > $TMP/SeTgateway clear break done # end main loop IP configuration } # end devconfig() # The PXE Server configuration routine: pxeconfig() { # This function accepts a parameter (network interface to configure). # If no name was passed, we will do our best to find out ourselves. # Create empty PXE configuration file: echo "" > $TMP/SeTpxe # Find out what interface we should be using. # Did we get one passed as a parameter? if [ "x$1" = "x" ]; then # No parameter or it was empty; find out if we have a wired interface: WIRED_INT="" IINT=0 for WINT in $(ls --indicator-style=none /sys/class/net |grep -v ^lo); do if ! grep -q $WINT /proc/net/wireless ; then WIRED_INT="$WIRED_INT $WINT" IINT=$(( $IINT + 1 )) fi done if [ $IINT -eq 0 ]; then # Zero wired interfaces found - exit. cat <<EOF > $TMP/tempmsg Could not find a wired network interface. \n\ A PXE Server needs a configured network interface to work.\n\ EOF if [ $DEBUG -ne 0 ]; then read -p "Press ENTER to continue: " JUNK ; fi $DIALOG --title "MISSING NETWORK DEVICE" --msgbox "$(cat $TMP/tempmsg)" 8 68 rm -f $TMP/tempmsg exit 1 elif [ $IINT -eq 1 ]; then # Exactly one wired interfaces found - use it. INTERFACE=$(echo $WIRED_INT) # get rid of the space else # Multiple wired interfaces found - let the user select one: rm -f $TMP/iflist for WINT in $WIRED_INT ; do DRIVERTXT="IP=$(ip -f inet -o addr show ${WINT} |tr -s ' ' |head -1 |cut - f4 -d' ' |cut -f1 -d/)" if cat /sys/class/net/$WINT/device/uevent 1>/dev/null 2>/dev/null ; then DRIVERTXT="$DRIVERTXT driver=$(grep "DRIVER=" /sys/class/net/$WINT/device/uevent |cut -f2 -d=)" fi echo "$WINT \"network interface ($DRIVERTXT)\"" >> $TMP/iflist done if [ $DEBUG -ne 0 ]; then read -p "Press ENTER to continue: " JUNK ; fi $DIALOG --title "SELECT NETWORK INTERFACE" \ --menu \ "Select an option below using the UP/DOWN keys and SPACE or ENTER.\n\ Alternate keys may also be used: '+', '-', and TAB." 13 72 9 \ --file $TMP/iflist \ 2> $TMP/intset INTERFACE="$(cat $TMP/intset)" rm $TMP/intset $TMP/iflist fi fi # End undefined INTERFACE # # We now know what network interface to use. # # If our interface is configured by DHCP, it likely has a lease from a # LAN DHCP server, so we should not activate another DHCP server ourself now: if [ -s $(get_dhcpcd_pid ${INTERFACE}) -a -n "$(ps -q $(cat $(get_dhcpcd_pid ${INTERFACE})) -o comm= 2>/dev/null)" ]; then OWNDHCP="no" elif [ -s $(get_nm_internal_lease ${INTERFACE}) ]; then OWNDHCP="no" else # Assume nothing... we will ask the user for confirmation later! OWNDHCP="yes" fi # If $INTERFACE != $GLOBAL_GW_INT then we are dealing with a dual-nic setup # and later on we can suggest configuring (NAT) routing: GLOBAL_GW_INT=$(ip -f inet -o route show default |grep -v linkdown |head -1 |tr -s ' ' |cut -f5 -d' ') GLOBAL_GATEWAY=$(ip -f inet -o route show default |grep -v linkdown |head -1 |tr -s ' ' |cut -f3 -d' ') # # Start the interactive part: # if [ $DEBUG -ne 0 ]; then read -p "Press ENTER to continue: " JUNK ; fi $DIALOG --backtitle "@CDISTRO@ Linux Live (@LIVEDE@) PXE Server." \ --title "WELCOME TO PXE CONFIGURATION" --msgbox "\ We will be asking you a few questions now.\n\ The answers will be used to start a PXE service on this computer \ which does not interfere with other services in your network.\ \n\ The only assumption is, that there is NO PXE service already \ running on your local network at this moment. \n\ If in doubt, stick with the defaults." 0 0 if [ "$OWNDHCP" = "yes" ]; then # Be extra safe. Do not start a DHCP server if the user denies it: if [ $DEBUG -ne 0 ]; then read -p "Press ENTER to continue: " JUNK ; fi $DIALOG --title "ENABLE DHCP SERVER" --yesno " \ Network interface ${INTERFACE} did not get an IP address from a DHCP server. \ Slackware's PXE server starting on ${INTERFACE} needs a working DHCP server.\n\ Do you want this computer to start its own DHCP server on ${INTERFACE} \ (you can control what IP addresses are used by the DHCP server)?\n\ Say 'YES' if you are certain your network interface ${INTERFACE} is not in reach of any DHCP server." 13 68 if [ $? = 0 ]; then OWNDHCP="yes" else OWNDHCP="no" fi fi if [ "$OWNDHCP" == "yes" ]; then if [ "$INTERFACE" != "$GLOBAL_GW_INT" ]; then # The default gateway for this computer is on another interface; $DIALOG --title "ENABLE NAT FIREWALL" --defaultno --yesno " \ This computer's default gateway is network interface ${GLOBAL_GW_INT}. \ The network behind the PXE server's interface ${INTERFACE} seems to be isolated.\n\ Do you want to hide your PXE clients behind a NAT gateway?\n\ This may be helpful if PXE clients cannot reach the external network otherwise.\n\ Say 'NO' if you are not sure which is best." 12 68 if [ $? = 0 ]; then ENABLE_NAT="yes" else ENABLE_NAT="no" fi fi fi # Assemble the network parameters: LOCAL_IPADDR=$(ip -f inet -o addr show ${INTERFACE} |tr -s ' ' |head -1 |cut -f4 -d' ' |cut -f1 -d/) if [ "x$LOCAL_IPADDR" = "x" ]; then # no IP Address was configured?!? cat <<EOF > $TMP/tempmsg Next step is to define an IP address for network interface ${INTERFACE}. \n\ A PXE Server needs a configured network interface to work.\n\ EOF if [ $DEBUG -ne 0 ]; then read -p "Press ENTER to continue: " JUNK ; fi $DIALOG --title "UNCONFIGURED NETWORK DEVICE" --msgbox "$(cat $TMP/tempmsg)" 9 68 rm -f $TMP/tempmsg # Run the static IP configuration routine for $INTERFACE: devconfig ${INTERFACE} else # DHCP configured interface, we assume that the default gaeway is here. LOCAL_GATEWAY=$GLOBAL_GATEWAY fi # OK we have an IP Address, let's continue. LOCAL_NETMASK=$(ip -f inet -o addr show ${INTERFACE} |tr -s ' ' |head -1 |cut -f4 -d' ' |cut -f2 -d/) LOCAL_NETMASK=$(cidr_cvt $LOCAL_NETMASK) LOCAL_BROADCAST=$(ipmask $LOCAL_NETMASK $LOCAL_IPADDR |cut -f 1 -d ' ') LOCAL_NETWORK=$(ipmask $LOCAL_NETMASK $LOCAL_IPADDR |cut -f 2 -d ' ') if [ "$OWNDHCP" = "yes" ]; then # Find out a suitable IP address range for the DHCP server. Involves magic: I_LOCAL_IPADDR=$(ip_to_int "$LOCAL_IPADDR") I_LOCAL_NETMASK=$(ip_to_int "$LOCAL_NETMASK") I_MINLEASE_IP=$(( ($I_LOCAL_IPADDR & $I_LOCAL_NETMASK) + 1 )) I_MAXLEASE_IP=$(( ($I_LOCAL_IPADDR | ${I_LOCAL_NETMASK}^0xffffffff) - 1 )) if [ $(( $I_MAXLEASE_IP - $I_LOCAL_IPADDR )) -ge $DEF_DHCP_RANGE ]; then # Use $DEF_DHCP_RANGE IP addresses in the top of the address range: I_MINLEASE_IP=$(( $I_MAXLEASE_IP - $(($DEF_DHCP_RANGE - 1)) )) elif [ $(($I_LOCAL_IPADDR - $I_MINLEASE_IP)) -ge $DEF_DHCP_RANGE ]; then # Use $DEF_DHCP_RANGE IP addresses in the bottom of the address range: I_MAXLEASE_IP=$(( $I_MINLEASE_IP + $(($DEF_DHCP_RANGE - 1)) )) else # Smaller range available than we wanted, use what we can get: I_MINLEASE_IP=$(( $I_LOCAL_IPADDR + 1 )) fi MINLEASE_IP=$(int_to_ip "$I_MINLEASE_IP") MAXLEASE_IP=$(int_to_ip "$I_MAXLEASE_IP") while [ 0 ]; do if [ $DEBUG -ne 0 ]; then read -p "Press ENTER to continue: " JUNK ; fi ( $DIALOG --stdout --backtitle "@CDISTRO@ Linux Live (@LIVEDE@) PXE Server." \ --title "DHCP SERVER CONFIGURATION" \ --cancel-label Restart \ --form "\ The PXE Service is going to run on $INTERFACE with these values \ (the defaults should be OK). \n\ You can change the range of IP addresses used by the DHCP server, if \ IP addresses in the proposed range are used by computers in your LAN. \ For instance, your default gateway if you have one. \n\ \n\ Also note that we will not validate any changes you make:" \ 18 68 0 \ "IP Address:" 1 1 "$LOCAL_IPADDR" 1 30 0 0 \ "Netmask:" 2 1 "$LOCAL_NETMASK" 2 30 0 0 \ "Gateway:" 3 1 "$LOCAL_GATEWAY" 3 30 0 0 \ "Lowest DHCP Client Address:" 4 1 "$MINLEASE_IP" 4 30 15 0 \ "Highest DHCP Client Address:" 5 1 "$MAXLEASE_IP" 5 30 15 0 \ ) > $TMP/tempopts if [ $? = 0 ]; then # Remember... busybox ash is no good with arrays :/ local i=0 rm -f $TMP/tempkeys cat $TMP/tempopts | while read VALUE ; do if [ $i = 0 ]; then echo "MINLEASE_IP=\"$VALUE\"" >> $TMP/tempkeys elif [ $i = 1 ]; then echo "MAXLEASE_IP=\"$VALUE\"" >> $TMP/tempkeys fi i=$(expr $i + 1) done eval $(cat $TMP/tempkeys) rm $TMP/tempopts break fi done else if [ $DEBUG -ne 0 ]; then read -p "Press ENTER to continue: " JUNK ; fi $DIALOG --backtitle "@CDISTRO@ Linux Live (@LIVEDE@) PXE Server." \ --title "DHCP SERVER CONFIGURATION" --msgbox "\ \n\ PXE server has been configured to use a DHCP server in your network.\n\ \n\ Press ENTER to continue." 14 68 fi # [ "$OWNDHCP" = "yes" ] echo "DHCP=${OWNDHCP}" >> $TMP/SeTpxe echo "GLOBAL_GATEWAY=${GLOBAL_GATEWAY}" >> $TMP/SeTpxe echo "GLOBAL_GW_INT=${GLOBAL_GW_INT}" >> $TMP/SeTpxe echo "LOCAL_IPADDR=${LOCAL_IPADDR}" >> $TMP/SeTpxe echo "LOCAL_NETMASK=${LOCAL_NETMASK}" >> $TMP/SeTpxe echo "LOCAL_GATEWAY=${LOCAL_GATEWAY}" >> $TMP/SeTpxe echo "LOCAL_BROADCAST=${LOCAL_BROADCAST}" >> $TMP/SeTpxe echo "LOCAL_NETWORK=${LOCAL_NETWORK}" >> $TMP/SeTpxe echo "MINLEASE_IP=${MINLEASE_IP}" >> $TMP/SeTpxe echo "MAXLEASE_IP=${MAXLEASE_IP}" >> $TMP/SeTpxe # Write out a suitable dnsmasq configuration: cat <<EOF > ${TMP}/pxe_dnsmasq.conf # Only listen at our designated interface: listen-address=$LOCAL_IPADDR # Write the pid file: pid-file=${TMP}/pxe_dnsmasq.pid # Start a TFTP server: enable-tftp # Set the root directory for files available via FTP: tftp-root=/var/lib/tftpboot # Disable re-use of the DHCP servername and filename fields as extra # option space. That's to avoid confusing some old or broken DHCP clients. dhcp-no-override # Log connections so that we can display them on the console: log-facility=/var/log/pxe_dnsmasq.log log-dhcp # Custom path for the leases file: dhcp-leasefile=$TMP/pxe_dnsmasq.leases # Test for the architecture of a netboot client. PXE clients are # supposed to send their architecture as option 93. (See RFC 4578) . # The known types are X86PC, PC98, IA64_EFI, Alpha, Arc_x86, # Intel_Lean_Client, IA32_EFI, BC_EFI, Xscale_EFI and X86-64_EFI dhcp-match=X86PC, option:client-arch, 0 #BIOS x86 dhcp-match=BC_EFI, option:client-arch, 7 #EFI Byte Code dhcp-match=X86-64_EFI, option:client-arch, 9 #EFI x86_64 # Craft a nice PXE menu (user has 3 seconds to interrupt in which case the # network boot sequence will be aborted): pxe-prompt="PXE booting in 3 seconds...", 3 # Now let's build a boot menu. If there's only one menu item PXE will # automatically boot into this. If thre are multiple boot selections, # then user input is expected. # I found out that UEFI PXE boot with more than one menu item won't work. # The 'pxe-service' definitions are the PXE alternative to the generic # 'dhcp-boot' keyword. # The PXE boot image has to match the client architecture. # And we enforce that our own TFTP server is being used so that misbehaving # DHCP servers on the LAN that set 'next-server' are not affecting us: pxe-service=X86PC, "Boot from network (BIOS)", pxelinux,${LOCAL_IPADDR} pxe-service=BC_EFI, "Boot from network (UEFI)", ${UEFIPREFIX}/bootx64.efi,${LOCAL_IPADDR} pxe-service=X86-64_EFI, "Boot from network (UEFI)", ${UEFIPREFIX}/bootx64.efi,${LOCAL_IPADDR} # A boot service type of 0 is special, and will abort the # net boot procedure and continue booting from local media. pxe-service=X86PC, "Boot from local hard disk", 0 # Note: # The above 'pxe-service' menu does not always work for UEFI-based clients, # so alternatively you could implement a combination of 'dhcp-match' and # 'dhcp-boot' to provide a boot image. Here is a commented-out example: #dhcp-match=set:BC_EFI,option:client-arch,7 #dhcp-match=set:X86-64_EFI,option:client-arch,9 #dhcp-match=set:X86_EFI,option:client-arch,6 #dhcp-match=set:X86PC,option:client-arch,0 #dhcp-boot=tag:X86-64_EFI,"${UEFIPREFIX}/bootx64.efi,${LOCAL_IPADDR}" #dhcp-boot=tag:BC_EFI,"${UEFIPREFIX}/bootx64.efi,${LOCAL_IPADDR}" #dhcp-boot=tag:X86_EFI,"${UEFIPREFIX}/bootia32.efi,${LOCAL_IPADDR}" #dhcp-boot=tag:X86PC,"pxelinux.0,${LOCAL_IPADDR}" EOF if [ -n "$LOCAL_GATEWAY" -a "$INTERFACE" = "$GLOBAL_GW_INT" ]; then # The default gw can be reached through our $INTERFACE. cat <<EOF >> ${TMP}/pxe_dnsmasq.conf # Override the default route supplied by dnsmasq, which assumes the # router is the same machine as the one running dnsmasq. # The two options below are equivalent: #dhcp-option=option:router,${LOCAL_GATEWAY} dhcp-option=3,${LOCAL_GATEWAY} EOF else # The default gw is reached through a second interface on the computer. # We need to build a router, a bridge or a NAT firewall between the two. cat <<EOF >> ${TMP}/pxe_dnsmasq.conf # Apply the default route supplied by dnsmasq, which assumes the # router is the same machine as the one running dnsmasq. # And we want to let our PXE clients use $INTERFACE as the default gw. #dhcp-option=option:router,${LOCAL_IPADDR} EOF fi if [ "$OWNDHCP" = "yes" ]; then cat <<EOF >> ${TMP}/pxe_dnsmasq.conf # dnsmasq functions as a normal DHCP server, providing IP leases. dhcp-range=${MINLEASE_IP},${MAXLEASE_IP},${LOCAL_NETMASK},1h EOF else cat <<EOF >> ${TMP}/pxe_dnsmasq.conf # There is an existing DHCP server on this LAN, so dnsmasq functions # as a proxy DHCP server providing boot information but no IP leases. # Any ip in the subnet will do, so you may just put your server NIC ip here. dhcp-range=${LOCAL_IPADDR},proxy EOF fi # Create the pxelinux configuration file for BIOS boot: KBD=$(sed -n "s%^ */usr/bin/loadkeys *%%p" /etc/rc.d/rc.keymap 2>/dev/null) cat <<EOF > /var/lib/tftpboot/pxelinux.cfg/default prompt 0 timeout 300 ui vesamenu.c32 default pxelive menu background swlogov.png menu title @CDISTRO@ Linux Live PXE boot menu menu clear F1 pxemessage.txt #00000000 F2 f2.txt #00000000 F3 f3.txt #00000000 F4 f4.txt #00000000 menu hshift 1 menu vshift 9 menu width 55 menu margin 1 menu rows 10 menu helpmsgrow 14 menu helpmsgendrow 18 menu cmdlinerow 18 menu tabmsgrow 19 menu timeoutrow 20 menu color screen 37;40 #00000000 #00000000 none menu color border 34;40 #00000000 #00000000 none menu color title 1;36;44 #ffb9556b #30002d1f none menu color unsel 37;44 #ff354172 #007591ff none menu color hotkey 1;37;44 #ffad37b7 #00000000 none menu color sel 7;37;40 #ffffffff #00000000 none menu color hotsel 1;7;37;40 #ffe649f3 #00000000 none menu color scrollbar 30;44 #00000000 #00000000 none menu color tabmsg 31;40 #ffA32222 #00000000 none menu color cmdmark 1;36;40 #ffff0000 #00000000 none menu color cmdline 37;40 #ffffffff #ff000000 none menu color pwdborder 30;47 #ffff0000 #00000000 std menu color pwdheader 31;47 #ffff0000 #00000000 std menu color pwdentry 30;47 #ffff0000 #00000000 std menu color timeout_msg 37;40 #ff809aef #00000000 none menu color timeout 1;37;40 #ffb72f9f #00000000 none menu color help 37;40 #ff354172 #00000000 none label pxelive menu label Boot @CDISTRO@ Linux Live (@LIVEDE@) from network kernel /generic append initrd=/initrd.img @KAPPEND@ load_ramdisk=1 prompt_ramdisk=0 rw printk.time=0 nfsroot=${LOCAL_IPADDR}:/mnt/livemedia luksvol= nop hostname=@DISTRO@ tz=$(cat /etc/timezone) locale=${SYSLANG:-"en_US.UTF-8"} kbd=${KBD:-"us"} EOF # And a Grub configuration for UEFI boot: cat <<EOF > /var/lib/tftpboot${UEFIPREFIX}/grub.cfg # PXE boot menu for UEFI based systems: set default=0 set timeout=200 # EFI video support: insmod efi_gop insmod efi_uga # (U)EFI requirement: must support all_video: insmod all_video # Load the network modules first, so that we can use \$prefix; insmod net insmod efinet insmod tftp insmod gzio insmod part_gpt insmod ext2 # Determine whether we can show a graphical themed menu: insmod font if loadfont \$prefix/theme/dejavusansmono12.pf2 ; then loadfont \$prefix/theme/dejavusansmono24.pf2 loadfont \$prefix/theme/dejavusansmono20.pf2 loadfont \$prefix/theme/dejavusansmono10.pf2 loadfont \$prefix/theme/dejavusansmono5.pf2 set font="DejaVu Sans Mono Regular 12" set gfxmode=1024x768,800x600,640x480,auto export gfxmode insmod gfxterm insmod gfxmenu terminal_output gfxterm insmod gettext insmod png set theme=\$prefix/theme/liveslak.txt export theme fi set gfxpayload=keep menuentry 'Boot @CDISTRO@ Linux Live (@LIVEDE@) from network' --class slackware --class gnu-linux --class gnu --class os { echo "Loading @CDISTRO@ kernel" linux generic @KAPPEND@ load_ramdisk=1 prompt_ramdisk=0 rw printk.time=0 nfsroot=${LOCAL_IPADDR}:/mnt/livemedia luksvol= nop hostname=@DISTRO@ tz=$(cat /etc/timezone) locale=${SYSLANG:-"en_US.UTF-8"} kbd=${KBD:-"us"} initrd initrd.img echo "Booting @CDISTRO@ kernel" } EOF } # end of pxeconfig() # -------------------------------------------------------- # # Above was just initialization and function definitions. # # Let's make use of all that. # # ---------------------------------------------------------# # Main loop: while [ 0 ]; do if [ $DEBUG -ne 0 ]; then read -p "Press ENTER to continue: " JUNK ; fi $DIALOG --title "@CDISTRO@ Linux Live PXE Server (@LIVEDE@ @SL_VERSION@)" \ --menu \ "Welcome to @CDISTRO@ Linux Live PXE Server.\n\ Select an option below using the UP/DOWN keys and SPACE or ENTER.\n\ Alternate keys may also be used: '+', '-', and TAB." 11 72 7 \ "NETWORK" "Configure your network parameters" \ "ACTIVATE" "Activate the @CDISTRO@ PXE Server" \ "EXIT" "Exit @CDISTRO@ PXE Setup" 2> $TMP/hdset if [ ! $? = 0 ]; then rm -f $TMP/hdset $TMP/SeT* exit fi MAINSELECT="`cat $TMP/hdset`" rm $TMP/hdset # Start checking what to do. Some modules may reset MAINSELECT to run the # next item in line. if [ "$MAINSELECT" = "NETWORK" ]; then # Set up our network. We may not know anything yet in which case # the variable $INTERFACE will be empty. pxeconfig $INTERFACE if [ -r $TMP/SeTpxe ]; then MAINSELECT="ACTIVATE" fi fi if [ "$MAINSELECT" = "ACTIVATE" ]; then if [ ! -r $TMP/SeTpxe ]; then if [ $DEBUG -ne 0 ]; then read -p "Press ENTER to continue: " JUNK ; fi $DIALOG --title "CANNOT START PXE SERVER YET" --msgbox "\ \n\ Before you can start the PXE Server, complete the following task:\n\ \n\ (*) Set up your computer's network parameters.\n\ \n\ Press ENTER to return to the main menu." 14 68 continue else if [ $DEBUG -ne 0 ]; then read -p "Press ENTER to continue: " JUNK ; fi $DIALOG --title "READY TO START PXE SERVER" --msgbox "\ \n\ Ready to start the PXE Server!\n\ The PXE server log will be displayed in the next screen. \n\ Press ENTER to start or ESCAPE to return to the main menu." 14 68 if [ $? -ne 0 ]; then # User did not press ENTER, let's return to main menu: continue fi fi # Time to start the BOOTP/TFTP/NFS servers: echo > /var/log/pxe_dnsmasq.log dnsmasq -C ${TMP}/pxe_dnsmasq.conf -z -i ${INTERFACE} if ! grep -q "^/mnt/livemedia" /etc/exports ; then # Without 'fsid' nfsd refuses to export the filesystem if it RAM based; # the number '14' could be any unique low-range number: cat <<EOT >> /etc/exports /mnt/livemedia ${LOCAL_NETWORK}/${LOCAL_NETMASK}(ro,sync,insecure,no_subtree_check,root_squash,fsid=14) EOT fi sh /etc/rc.d/rc.nfsd restart if [ "$INTERFACE" != "$GLOBAL_GW_INT" ]; then # The default gateway for this computer is on another interface; # we need to enable forwarding: OLDROUTING=$(cat /proc/sys/net/ipv4/ip_forward) echo 1 > /proc/sys/net/ipv4/ip_forward if [ "${ENABLE_NAT}" == "yes" ]; then # Add NAT firewall rule: iptables -t nat -A POSTROUTING -o ${GLOBAL_GW_INT} -j MASQUERADE iptables -A FORWARD -p ALL -i ${GLOBAL_GW_INT} -j ACCEPT iptables -A FORWARD -m state --state ESTABLISHED,RELATED -i ${GLOBAL_GW_INT} -j ACCEPT else if [ -z "$(pidof routed)" ]; then # Also start the route daemon: /usr/sbin/routed -g -s /var/log/routed_pxeserver.log fi fi else OLDROUTING="" fi if [ $DEBUG -ne 0 ]; then read -p "Press ENTER to continue: " JUNK ; fi $DIALOG --backtitle "@CDISTRO@ Linux Live PXE Server." \ --title "PXE Client activity log" \ --ok-label "EXIT" \ --tailbox /var/log/pxe_dnsmasq.log 20 68 # Time to kill the BOOTP/TFTP/NFS servers and revert network settings: if [ "${ENABLE_NAT}" == "yes" ]; then # Remove NAT firewall rule: iptables -D FORWARD -m state --state ESTABLISHED,RELATED -i ${GLOBAL_GW_INT} -j ACCEPT iptables -D FORWARD -p ALL -i ${GLOBAL_GW_INT} -j ACCEPT iptables -t nat -D POSTROUTING -o ${GLOBAL_GW_INT} -j MASQUERADE fi if [ -n "$OLDROUTING" ]; then echo $OLDROUTING > /proc/sys/net/ipv4/ip_forward fi kill -TERM $(cat ${TMP}/pxe_dnsmasq.pid) sh /etc/rc.d/rc.nfsd stop sed -i -e "s%^/mnt/livemedia.*%#&%" /etc/exports fi if [ "$MAINSELECT" = "EXIT" ]; then clear if [ -x /etc/rc.d/rc.networkmanager 2>/dev/null ]; then # Use nmcli to remove the NetworkManager connection: nmcli con down pxe-${INTERFACE} nmcli con del pxe-${INTERFACE} else # Manually bring the interface down: dhcpcd -k ${INTERFACE} 2>/dev/null ip link set dev ${INTERFACE} down ip address flush dev ${INTERFACE} fi break fi done # end of main loop # end @CDISTRO@ Linux Live PXE Server script