From: Michael Tremer Date: Thu, 17 May 2012 15:23:58 +0000 (+0000) Subject: Add basic support as a DHCP client. X-Git-Tag: 004~88 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=e9ea243e89e1091cf9b1a509399bd8e80b513d54;p=network.git Add basic support as a DHCP client. --- diff --git a/Makefile b/Makefile index 7d51cc62..3be147e1 100644 --- a/Makefile +++ b/Makefile @@ -26,6 +26,10 @@ install: # Install bridge-stp. install -m 755 bridge-stp $(DESTDIR)/sbin/ + # Install dhclient script and helper. + install -m 755 dhclient-helper ${DESTDIR}/usr/lib/network/ + install -m 755 dhclient-script ${DESTDIR}/sbin/ + install -m 755 -v ppp/ip-updown $(DESTDIR)/etc/ppp ln -svf ip-updown $(DESTDIR)/etc/ppp/ip-pre-up ln -svf ip-updown $(DESTDIR)/etc/ppp/ip-up diff --git a/dhclient-helper b/dhclient-helper new file mode 100644 index 00000000..8401146a --- /dev/null +++ b/dhclient-helper @@ -0,0 +1,60 @@ +#!/bin/bash + +. /usr/lib/network/functions + +action="${1}" +assert isset action + +interface="${2}" +assert isset interface + +proto=${3} +assert isset proto + +# Check if the given interface is a zone. +assert zone_exists ${interface} + +case "${action}" in + start) + # Create dhclient configuration file. + case "${proto}" in + ipv4) + config_file="${RUN_DIR}/dhclient/${interface}/dhclient4.conf" + ;; + ipv6) + config_file="${RUN_DIR}/dhclient/${interface}/dhclient6.conf" + ;; + esac + assert isset config_file + + dhclient_write_config ${interface} ${config_file} \ + --hostname="${HOSTNAME%%.*}" + + exit ${EXIT_OK} + ;; + + stop) + case "${proto}" in + ipv4) + reason="STOP" + ;; + ipv6) + reason="STOP6" + ;; + esac + assert isset reason + + export interface + export reason + + exec /usr/sbin/dhclient-script + + log ERROR $"execing dhclient-script has failed." + exit ${EXIT_ERROR} + ;; + + *) + log ERROR "Unknown action passed: ${action}" + exit ${EXIT_ERROR} + ;; +esac diff --git a/dhclient-script b/dhclient-script new file mode 100644 index 00000000..e56c096c --- /dev/null +++ b/dhclient-script @@ -0,0 +1,122 @@ +#!/bin/bash + +. /usr/lib/network/functions + +# Configure logging +LOG_FACILITY="dhclient-script" + +assert isset interface +assert isset reason + +assert device_exists ${interface} + +# XXX LOAD ZONE CONFIGURATION + +basename="$(basename $0)" +log DEBUG "${basename} called for interface=${interface} reason=${reason}" + +# Main pitchfork. +case "${reason}" in + MEDIUM) + # Linux does not handle MEDIUM. + exit 0 + ;; + + PREINIT) + # Bring up the device if it hasn't been done before. + if ! device_is_up ${interface}; then + log DEBUG "The interface '${interface}' does not appear to be up." + + zone_up ${interface} + fi + + # If the use configured a delay, we will honour that. + if [ -n "${DELAY}" ]; then + assert isinteger DELAY + sleep ${DELAY} + + # If he didn't, we will try to detect is STP has brought the + # bridge up. + elif device_is_bridge ${interface}; then + counter=60 + + while [ ${counter} -gt 0 ]; do + # We may end this, when the bridge is in forwarding mode. + if bridge_is_forwarding ${interface}; then + log DEBUG "Bridge '${interface}' is in forwarding mode." + break + fi + + counter=$(( ${counter} - 1 )) + sleep 1 + done + + # Tell the daemon, that we are not ready to go on. + if [ ${counter} -eq 0 ]; then + log ERROR "Bridge '${interface}' is not in forwarding mode." + log ERROR "Could not go on with getting a DHCP lease. Exiting." + + exit 1 + fi + fi + + exit 0 + ;; + + + BOUND|RENEW|REBIND|REBOOT) + # Check if the IP address has changed. If so, delete all routes and stuff. + if [ -n "${old_ip_address}" -a "${old_ip_address}" != "${new_ip_address}" ]; then + ipv4_flush_device ${interface} + fi + + case "${reason}" in + BOUND|REBOOT) + if [ ! "${old_ip_address}" = "${new_ip_address}" ] || \ + [ ! "${old_subnet_mask}" = "${new_subnet_mask}" ] || \ + [ ! "${old_network_number}" = "${new_network_number}" ] || \ + [ ! "${old_broadcast_address}" = "${new_broadcast_address}" ] || \ + [ ! "${old_routers}" = "${new_routers}" ] || \ + [ ! "${old_interface_mtu}" = "${new_interface_mtu}" ]; then + + + # Calc a prefix out of address and subnet mask. + new_prefix="$(ipv4_get_prefix ${new_ip_address} ${new_subnet_mask})" + + # Set the new ip address. + ip_address_add ${interface} ${new_ip_address}/${new_prefix} + device_set_up ${interface} + + + # A MTU of 576 is used for X.25 and dialup connections. Some broken DHCP + # servers send out an MTU of 576 bytes, which will be ignored. + if [ -n "${new_interface_mtu}" ] && [ ${new_interface_mtu} -gt 576 ]; then + device_set_mtu ${interface} ${new_interface_mtu} + fi + + # Save configuration + routing_db_set ${interface} ipv4 type "ipv4-dhcp" + routing_db_set ${interface} ipv4 local-ip-address "${new_ip_address}/${new_prefix}" + routing_db_set ${interface} ipv4 remote-ip-address "${new_router}" + routing_db_set ${interface} ipv4 active 1 + + # Update the routing tables. + routing_update ${interface} ipv4 + fi + ;; + esac + + exit 0 + ;; + + EXPIRE|FAIL|RELEASE|STOP) + # Remove the currently configured addresses from the device. + if [ -n "${old_ip_address}" ]; then + ipv4_flush_device ${interface} + fi + + exit 0 + ;; +esac + +exit 1 diff --git a/functions b/functions index e3d95fb4..6ced711e 100644 --- a/functions +++ b/functions @@ -17,9 +17,9 @@ function init_run() { } # Include version information. -. /lib/network/version +. /usr/lib/network/version -for file in /lib/network/functions.*; do +for file in /usr/lib/network/functions.*; do . ${file} done diff --git a/functions.cli b/functions.cli index 411188da..e2599637 100644 --- a/functions.cli +++ b/functions.cli @@ -541,5 +541,5 @@ function cli_get_key() { } function cli_get_val() { - echo "${1##*=}" + echo "${@##*=}" } diff --git a/functions.constants b/functions.constants index 90c1409b..b73b9267 100644 --- a/functions.constants +++ b/functions.constants @@ -19,6 +19,9 @@ # # ############################################################################### +# Set gettext text domain. +TEXTDOMAIN="network" + # Enable colors by default COLOURS="auto" diff --git a/functions.dhclient b/functions.dhclient new file mode 100644 index 00000000..e20ad149 --- /dev/null +++ b/functions.dhclient @@ -0,0 +1,126 @@ +#!/bin/bash +############################################################################### +# # +# IPFire.org - A linux based firewall # +# Copyright (C) 2012 IPFire Network Development Team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +############################################################################### + +dhclient_start() { + local interface=${1} + local proto=${2} + + assert isset interface + assert device_exists ${interface} + + local service=$(dhclient_proto2service ${proto}) + assert isset service + + service_start "${service}@${interface}" +} + +dhclient_stop() { + local interface=${1} + local proto=${2} + + local service=$(dhclient_proto2service ${proto}) + assert isset service + + service_stop "${service}@${interface}" +} + +dhclient_proto2service() { + local proto=${1} + assert isset proto + + local service + + case "${proto}" in + ipv4) + service="dhclient4" + ;; + ipv6) + service="dhclient6" + ;; + *) + return ${EXIT_ERROR} + ;; + esac + + assert isset service + + echo "${service}" + return ${EXIT_OK} +} + +dhclient_write_config() { + local interface=${1} + local file=${2} + shift 2 + + assert isset interface + assert isset file + + local hostname=${HOSTNAME%%.*} + local vendor=$(distro_get_pretty_name) + + while [ $# -gt 0 ]; do + case "${1}" in + --hostname=*) + hostname=$(cli_get_val ${1}) + ;; + --vendor=*) + vendor=$(cli_get_val ${1}) + ;; + *) + log WARNING $"Unknown configuration option passed: ${1}." + ;; + esac + shift + done + + # Clear configuration file (if any). + mkdir -p $(dirname ${file}) 2>/dev/null + : > ${file} + + # Print the header. + ( echo "#" + echo "# This is a dhclient daemon configuration file for ${interface}." + echo "# THIS FILE IS AUTOMATICALLY GENERATED AND WILL OVERWRITE" + echo "# ANY CUSTOM CHANGES!" + echo "#" + echo "# $(date -u)" + echo "#" + echo + ) >>${file} + + # Global options. + echo "send vendor-class-identifier \"${vendor}\";" >>${file} + echo + + # Interface options. + ( + echo "interface \"${interface}\" {" + + if isset hostname; then + echo " send host-name \"${hostname}\";" + fi + + echo "}" + ) >>${file} + + return ${EXIT_OK} +} diff --git a/functions.distro b/functions.distro new file mode 100644 index 00000000..4dc831b8 --- /dev/null +++ b/functions.distro @@ -0,0 +1,57 @@ +#!/bin/bash +############################################################################### +# # +# IPFire.org - A linux based firewall # +# Copyright (C) 2012 IPFire Network Development Team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +############################################################################### + +__os_release() { + local what=${1} + + assert [ -e "/etc/os-release" ] + + local line k v + while read line; do + k=$(cli_get_key ${line}) + v=$(cli_get_val ${line}) + + if [ "${what}" = "${k}" ]; then + echo "${v//\"/}" + break + fi + done < /etc/os-release +} + +distro_get_name() { + __os_release NAME +} + +distro_get_version() { + __os_release VERSION +} + +distro_get_id() { + __os_release ID +} + +distro_get_version_id() { + __os_release VERSION_ID +} + +distro_get_pretty_name() { + __os_release PRETTY_NAME +} diff --git a/functions.ipv4 b/functions.ipv4 index d074ca94..1220d491 100644 --- a/functions.ipv4 +++ b/functions.ipv4 @@ -73,3 +73,34 @@ function ipv4_get_netaddress() { return ${EXIT_OK} } + +function ipv4_get_prefix() { + local address=${1} + local broadcast=${2} + + assert isset address + assert isset broadcast + + local PREFIX + eval $(ipcalc --prefix ${address} ${broadcast}) + assert isset PREFIX + + echo "${PREFIX}" + return ${EXIT_OK} +} + +function ipv4_flush_device() { + # + # Flushes all routes, addresses from the device + # and clears the ARP cache. + # + + local device=${1} + assert isset device + + ip -4 addr flush dev ${device} >/dev/null 2>&1 + ip -4 route flush dev ${device} >/dev/null 2>&1 + ip -4 neigh flush dev ${device} >/dev/null 2>&1 + + return 0 +} diff --git a/hooks/zones/bridge.configs/ipv4-dhcp b/hooks/zones/bridge.configs/ipv4-dhcp new file mode 100755 index 00000000..fd5f1c64 --- /dev/null +++ b/hooks/zones/bridge.configs/ipv4-dhcp @@ -0,0 +1,111 @@ +#!/bin/bash +############################################################################### +# # +# IPFire.org - A linux based firewall # +# Copyright (C) 2010 Michael Tremer & Christian Schmidt # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +############################################################################### + +. /lib/network/header-config + +HOOK_SETTINGS="HOOK DELAY" + +# Default settings. +DELAY=0 + +function _check() { + assert isset DELAY + assert isinteger DELAY +} + +function _create() { + local zone=${1} + shift + + while [ $# -gt 0 ]; do + case "${1}" in + --delay=*) + DELAY=${1#--delay=} + ;; + esac + shift + done + + config_write $(zone_dir ${zone})/configs/${HOOK} ${HOOK_SETTINGS} + + exit ${EXIT_OK} +} + +function _up() { + local zone=${1} + local config=${2} + shift 2 + + if ! device_exists ${zone}; then + error "Zone '${zone}' doesn't exist." + exit ${EXIT_ERROR} + fi + + # Start dhclient for IPv4 on this zone. + dhclient_start ${zone} ipv4 + + exit ${EXIT_OK} +} + +function _down() { + local zone=${1} + local config=${2} + shift 2 + + if ! device_exists ${zone}; then + error "Zone '${zone}' doesn't exist." + exit ${EXIT_ERROR} + fi + + # Stop dhclient for IPv4 on this zone. + dhclient_stop ${zone} ipv4 + + exit ${EXIT_OK} +} + +function _status() { + local zone=${1} + local config=${2} + shift 2 + + if ! device_exists ${zone}; then + error "Zone '${zone}' doesn't exist." + exit ${EXIT_ERROR} + fi + + config_read $(zone_dir ${zone})/configs/${config} + + printf " %10s - " "${HOOK}" + if zone_has_ip ${zone} ${ADDRESS}/${PREFIX}; then + echo -ne "${COLOUR_UP} UP ${COLOUR_NORMAL}" + else + echo -ne "${COLOUR_DOWN}DOWN${COLOUR_NORMAL}" + fi + echo " - ${ADDRESS}/${PREFIX}" + + if [ -n "${GATEWAY}" ]; then + echo " Gateway: ${GATEWAY}" + fi + + exit ${EXIT_OK} +} + +run $@