X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=network;h=5a5aba2899fb36e7fd1207aa07051b14a58ccbad;hb=1206f44c8c0843315608fd030a742e16d7b43bd8;hp=2309848272c0eb1758d95482ccddd394a8c1b6a4;hpb=b8357295110941bea1946f708d96673c7729db23;p=people%2Fstevee%2Fnetwork.git diff --git a/network b/network index 23098482..5a5aba28 100755 --- a/network +++ b/network @@ -19,14 +19,11 @@ # # ############################################################################### -. /lib/network/functions - # Parse the command line while [ $# -gt 0 ]; do case "${1}" in -d|--debug) DEBUG=1 - log DEBUG "Enabled debugging mode" ;; *) action=${1} @@ -36,24 +33,1096 @@ while [ $# -gt 0 ]; do [ -n "${action}" ] && break done +. /usr/lib/network/functions + +# Read network configuration. +network_config_read + +function cli_config() { + if cli_help_requested $@; then + cli_show_man network-config + exit ${EXIT_OK} + fi + + if [ -n "${1}" ]; then + config_set $@ + network_config_write + else + network_config_print + fi +} + +function cli_device() { + if cli_help_requested $@; then + cli_show_man network-device + exit ${EXIT_OK} + fi + + local device=${1} + local action=${2} + shift 2 + + if ! isset device; then + cli_show_man network-device + return ${EXIT_ERROR} + fi + + assert device_exists ${device} + + case "${action}" in + discover) + cli_device_discover ${device} $@ + ;; + status) + cli_device_status ${device} + ;; + unlock) + cli_device_serial_unlock ${device} $@ + ;; + *) + cli_show_man network-device + ;; + esac + + return ${EXIT_OK} +} + +function cli_device_status() { + local device=${1} + assert device_exists ${device} + + # Disable debugging output here. + local log_disable_stdout=${LOG_DISABLE_STDOUT} + LOG_DISABLE_STDOUT="true" + + # Save the type of the device for later. + local type=$(device_get_type ${device}) + + cli_headline 1 "Device status: ${device}" + cli_print_fmt1 1 "Name" "${device}" + + # Handle serial devices. + if [ "${type}" = "serial" ]; then + cli_device_status_serial ${device} + return $? + fi + + # Print the device status. + device_is_up ${device} &>/dev/null + local status=$? + + case "${status}" in + ${EXIT_TRUE}) + status="${CLR_GREEN_B}UP${CLR_RESET}" + ;; + ${EXIT_FALSE}) + status="${CLR_RED_B}DOWN${CLR_RESET}" + ;; + esac + + cli_print_fmt1 1 "Status" "${status}" + cli_print_fmt1 1 "Type" "${type}" + cli_print_fmt1 1 "Address" "$(device_get_address ${device})" + cli_space + + # Print the link speed for ethernet devices. + if device_is_up ${device} &>/dev/null; then + case "${type}" in + ethernet) + cli_print_fmt1 1 "Link" \ + "$(device_get_speed ${device}) MBit/s $(device_get_duplex ${device}) duplex" + ;; + esac + fi + + cli_print_fmt1 1 "MTU" "$(device_get_mtu ${device})" + cli_space + + # Print device statistics. + cli_device_stats 2 ${device} + + # Print some more information. + device_has_carrier ${device} &>/dev/null + cli_print_fmt1 1 "Has carrier?" "$(cli_print_bool $?)" + + device_is_promisc ${device} &>/dev/null + cli_print_fmt1 1 "Promisc" "$(cli_print_bool $?)" + cli_space + + # Print all vlan devices. + local vlans=$(device_get_vlans ${device}) + if [ -n "${vlans}" ]; then + cli_headline 2 "VLAN devices" + + local vlan + for vlan in ${vlans}; do + cli_print 2 "* %-6s - %s" "${vlan}" "$(device_get_address ${vlan})" + done + cli_space + fi + + # Reset the logging level. + LOG_DISABLE_STDOUT=${log_disable_stdout} +} + +function cli_device_status_serial() { + local device=${1} + assert device_is_serial ${device} + + serial_is_locked ${device} &>/dev/null + local locked=$? + + cli_print_fmt1 1 "Locked" "$(cli_print_bool ${locked})" + cli_space + + # Cannot go on when the device is locked. + [ ${locked} -eq ${EXIT_TRUE} ] && return ${EXIT_OK} + + cli_print_fmt1 1 "Manufacturer" \ + "$(modem_get_manufacturer ${device})" + cli_print_fmt1 1 "Model" \ + "$(modem_get_model ${device})" + cli_print_fmt1 1 "Software version" \ + "$(modem_get_software_version ${device})" + + if modem_is_mobile ${device}; then + cli_print_fmt1 1 "IMEI" \ + "$(modem_get_device_imei ${device})" + cli_space + + cli_headline 2 "Network status" + modem_sim_status ${device} &>/dev/null + local sim_status_code=$? + + local sim_status="unknown" + case "${sim_status_code}" in + ${EXIT_SIM_READY}) + sim_status="SIM ready" + ;; + ${EXIT_SIM_PIN}) + sim_status="PIN locked" + ;; + ${EXIT_SIM_PUK}) + sim_status="PUK locked" + ;; + esac + cli_print_fmt1 2 "SIM status" "${sim_status}" + + if [ ${sim_status_code} -eq ${EXIT_SIM_READY} ]; then + cli_print_fmt1 2 "IMSI" \ + "$(modem_get_sim_imsi ${device})" + cli_print_fmt1 2 "Operator" \ + "$(modem_get_network_operator ${device})" + cli_print_fmt1 2 "Mode" \ + "$(modem_get_network_mode ${device})" + cli_print_fmt1 2 "Signal quality" \ + "$(modem_get_signal_quality ${device}) dBm" + + local ber=$(modem_get_bit_error_rate ${device}) + isset ber || ber="unknown" + cli_print_fmt1 2 "Bit Error Rate" "${ber}" + fi + fi + cli_space +} + +function cli_device_discover() { + local device=${1} + shift + + local device_type=$(device_get_type ${device}) + if [ "${device_type}" != "real" ]; then + return ${EXIT_OK} + fi + + local raw + + while [ $# -gt 0 ]; do + case "${1}" in + --raw) + raw=1 + ;; + esac + shift + done + + local up + device_is_up ${device} && up=1 + device_set_up ${device} + + enabled raw || echo "${device}" + + local hook + local out + local ret + for hook in $(hook_zone_get_all); do + out=$(hook_zone_exec ${hook} discover ${device}) + ret=$? + + [ ${ret} -eq ${DISCOVER_NOT_SUPPORTED} ] && continue + + if enabled raw; then + case "${ret}" in + ${DISCOVER_OK}) + echo "${hook}: OK" + local line + while read line; do + echo "${hook}: ${line}" + done <<<"${out}" + ;; + + ${DISCOVER_ERROR}) + echo "${hook}: FAILED" + ;; + esac + else + case "${ret}" in + ${DISCOVER_OK}) + echo " ${hook} was successful." + local line + while read line; do + echo " ${line}" + done <<<"${out}" + ;; + + ${DISCOVER_ERROR}) + echo " ${hook} failed." + ;; + esac + fi + done + + echo # New line + + [ "${up}" = "1" ] || device_set_down ${device} +} + +function cli_device_serial_unlock() { + if cli_help_requested $@; then + cli_show_man network-device + exit ${EXIT_OK} + fi + + local device=${1} + assert isset device + + if ! device_is_serial ${device}; then + error "${device} is not a serial device." + error "Unlocking is only supported for serial devices." + exit ${EXIT_ERROR} + fi + + # Read the current state of the SIM card. + modem_sim_status ${device} &>/dev/null + local sim_status_code=$? + + # If the SIM card is already unlocked, we don't need to do anything. + if [ ${sim_status_code} -eq ${EXIT_SIM_READY} ]; then + print "The SIM card is already unlocked." + exit ${EXIT_OK} + + # If the SIM card is in an unknown state, we cannot do anything. + elif [ ${sim_status_code} -eq ${EXIT_SIM_UNKNOWN} ]; then + error "The SIM card is in an unknown state." + exit ${EXIT_ERROR} + fi + + # Ask for the code. + local code=${2} + local require_new_pin="false" + local new_pin + + while ! isinteger code; do + local message + case "${sim_status_code}" in + ${EXIT_SIM_PIN}) + message="Please enter PIN:" + ;; + ${EXIT_SIM_PUK}) + message="Please enter PUK:" + require_new_pin="true" + ;; + esac + assert isset message + + echo -n "${message} " + read -s code + echo # Print newline. + + if enabled require_new_pin; then + local i new_pin2 + for i in 0 1; do + case "${i}" in + 0) + message="Please enter a new PIN code:" + ;; + 1) + message="Please confirm the new PIN code:" + ;; + esac + + echo -n "${message} " + read -s new_pin2 + echo # Print newline. + + if [ -n "${new_pin}" ]; then + if [ "${new_pin}" != "${new_pin2}" ]; then + error "The entered PIN codes did not match." + exit ${EXIT_ERROR} + fi + else + new_pin=${new_pin2} + fi + done + fi + done + + # Trying to unlock the SIM card. + modem_sim_unlock ${device} ${code} ${new_pin} + + exit $? +} + +function cli_hostname() { + if cli_help_requested $@; then + cli_show_man network + exit ${EXIT_OK} + fi + + local hostname=${1} + + if [ -n "${hostname}" ]; then + config_hostname ${hostname} + log INFO "Hostname was set to '${hostname}'." + log INFO "Changes do only take affect after reboot." + exit ${EXIT_OK} + fi + + echo "$(config_hostname)" + exit ${EXIT_OK} +} + +function cli_port() { + if cli_help_requested $@; then + cli_show_man network-port + exit ${EXIT_OK} + fi + + local action + local port + + if port_exists ${1}; then + port=${1} + action=${2} + shift 2 + + # Action aliases + case "${action}" in + start) + action="up" + ;; + stop) + action="down" + ;; + show) + action="status" + ;; + esac + + case "${action}" in + edit|up|down|status) + port_${action} ${port} $@ + ;; + *) + error "Unrecognized argument: ${action}" + exit ${EXIT_ERROR} + ;; + esac + else + action=${1} + shift + + case "${action}" in + create|destroy) + port_${action} $@ + ;; + *) + error "Unrecognized argument: ${action}" + exit ${EXIT_ERROR} + ;; + esac + fi +} + +function cli_zone() { + if cli_help_requested $@; then + cli_show_man network-zone + exit ${EXIT_OK} + fi + + local action + local zone + + if zone_name_is_valid ${1}; then + zone=${1} + action=${2} + shift 2 + + # Action aliases + case "${action}" in + start) + action="up" + ;; + stop) + action="down" + ;; + show) + action="status" + ;; + esac + + case "${action}" in + config|down|edit|port|status|up) + zone_${action} ${zone} $@ + ;; + *) + error "Unrecognized argument: ${action}" + cli_show_man network-zone + exit ${EXIT_ERROR} + ;; + esac + else + action=${1} + shift + + case "${action}" in + create) + zone_${action} $@ + ;; + remove) + cli_zone_remove $@ + ;; + list-hooks) + cli_list_hooks zone $@ + ;; + ""|*) + if [ -n "${action}" ]; then + error "Unrecognized argument: '${action}'" + echo + fi + + cli_show_man network-zone + exit ${EXIT_ERROR} + ;; + esac + fi +} + +# Removes a zone either immediately, if it is currently down, +# or adds a tag that the removal will be done when the zone +# is brought down the next time. +function cli_zone_remove() { + if cli_help_requested $@; then + cli_show_man network-zone + exit ${EXIT_OK} + fi + + local zone=${1} + assert zone_exists ${zone} + + if zone_is_up ${zone}; then + echo "Zone '${zone}' is up and will be removed when it goes down the next time." + zone_remove ${zone} + else + echo "Removing zone '${zone}' now..." + zone_remove_now ${zone} + fi + + exit ${EXIT_OK} +} + +function cli_list_hooks() { + local type=${1} + shift + + if cli_help_requested $@; then + cli_show_man network-zone + exit ${EXIT_OK} + fi + + local hook_dir=$(hook_dir ${type}) + local hook + + for hook in ${hook_dir}/*; do + hook=$(basename ${hook}) + if hook_exists ${type} ${hook}; then + echo "${hook}" + fi + done | sort -u +} + +function cli_route() { + if cli_help_requested $@; then + cli_show_man network-route + exit ${EXIT_OK} + fi + + local action=${1} + shift + + case "${action}" in + # Add a new route. + add) + route_add $@ + ;; + # Remove an existing route. + remove) + route_remove $@ + ;; + # List all routes. + list) + route_list $@ + return ${EXIT_OK} + ;; + *) + error "Unrecognized action: ${action}" + cli_run_help network route + + exit ${EXIT_ERROR} + ;; + esac + + # Applying all routes. + route_apply + + exit ${EXIT_OK} +} + +function cli_dhcpd() { + local proto=${1} + shift + + if cli_help_requested $@; then + cli_show_man network-dhcp + exit ${EXIT_OK} + fi + + local action=${1} + shift + + case "${action}" in + edit) + dhcpd_edit ${proto} $@ + ;; + start) + dhcpd_start ${proto} + ;; + stop) + dhcpd_stop ${proto} + ;; + restart|reload) + dhcpd_reload ${proto} + ;; + subnet) + cli_dhcpd_subnet ${proto} $@ + ;; + show|"") + cli_dhcpd_show ${proto} $@ + ;; + *) + error "Unrecognized action: ${action}" + cli_run_help network dhcpvN + + exit ${EXIT_ERROR} + ;; + esac + + exit ${EXIT_OK} +} + +function cli_dhcpd_show() { + local proto=${1} + assert isset proto + + local settings=$(dhcpd_settings ${proto}) + assert isset settings + + local ${settings} + dhcpd_global_settings_read ${proto} + + cli_headline 1 "Dynamic Host Configuration Protocol Daemon for ${proto/ip/IP}" + + case "${proto}" in + ipv6) + cli_headline 2 "Lease times" + if isinteger VALID_LIFETIME; then + cli_print_fmt1 2 "Valid lifetime" "${VALID_LIFETIME}s" + fi + + if isinteger PREFERRED_LIFETIME; then + cli_print_fmt1 2 "Preferred lifetime" "${PREFERRED_LIFETIME}s" + fi + + cli_space + ;; + ipv4) + cli_print_fmt1 1 "Authoritative" $(cli_print_enabled AUTHORITATIVE) + cli_space + + cli_headline 2 "Lease times" + cli_print_fmt1 2 "Default lease time" "${DEFAULT_LEASE_TIME}s" + cli_print_fmt1 2 "Max. lease time" "${MAX_LEASE_TIME}s" + + if isset MIN_LEASE_TIME; then + cli_print_fmt1 2 "Min. lease time" "${MIN_LEASE_TIME}s" + fi + + cli_space + ;; + esac + + # Read the options. + local -A options + dhcpd_global_options_read ${proto} ${subnet_id} + + # Print the options if any. + if [ ${#options[*]} -gt 0 ]; then + cli_headline 2 "Options" + + local option + for option in $(dhcpd_options ${proto}); do + [ -n "${options[${option}]}" ] || continue + + cli_print_fmt1 2 \ + "${option}" "${options[${option}]}" + done + cli_space + fi + + # Subnets. + local subnets=$(dhcpd_subnet_list ${proto}) + if [ -n "${subnets}" ]; then + cli_headline 2 "Subnets" + local subnet_id + for subnet_id in ${subnets}; do + cli_dhcpd_subnet_show ${proto} ${subnet_id} 2 + done + fi +} + +function cli_dhcpd_subnet() { + local proto=${1} + shift + + if cli_help_requested $@; then + cli_show_man network-dhcp-subnet + exit ${EXIT_OK} + fi + + local action=${1} + shift + + case "${action}" in + new) + dhcpd_subnet_new ${proto} $@ + ;; + remove) + dhcpd_subnet_remove ${proto} $@ + ;; + [0-9]*) + local subnet_id=${action} + + if ! dhcpd_subnet_exists ${proto} ${subnet_id}; then + error "The given subnet with ID ${subnet_id} does not exist." + return ${EXIT_ERROR} + fi + + # Update the action. + action=${1} + shift + + case "${action}" in + edit) + dhcpd_subnet_edit ${proto} ${subnet_id} $@ + local ret=$? + + if [ ${ret} -eq ${EXIT_OK} ]; then + dhcpd_reload ${proto} + fi + exit ${ret} + ;; + range) + cli_dhcpd_subnet_range ${proto} ${subnet_id} $@ + exit $? + ;; + show) + cli_dhcpd_subnet_show ${proto} ${subnet_id} $@ + exit $? + ;; + options) + cli_dhcpd_subnet_options ${proto} ${subnet_id} $@ + exit $? + ;; + *) + error "Unrecognized action: ${action}" + cli_run_help network dhcpvN subnet + exit ${EXIT_ERROR} + ;; + esac + ;; + show) + local subnet_id + for subnet_id in $(dhcpd_subnet_list ${proto}); do + cli_dhcpd_subnet_show ${proto} ${subnet_id} + done + ;; + *) + error "Unrecognized action: ${action}" + cli_run_help network dhcpvN subnet + + exit ${EXIT_ERROR} + ;; + esac + + exit ${EXIT_OK} +} + +function cli_dhcpd_subnet_range() { + local proto=${1} + assert isset proto + shift + + local subnet_id=${1} + assert isset subnet_id + shift + + local action=${1} + shift + + case "${action}" in + new) + dhcpd_subnet_range_new ${proto} ${subnet_id} $@ + exit $? + ;; + remove) + dhcpd_subnet_range_remove ${proto} ${subnet_id} $@ + exit $? + ;; + *) + error "Unrecognized action: ${action}" + cli_run_help network dhcpvN subnet range + exit ${EXIT_ERROR} + ;; + esac +} + +function cli_dhcpd_subnet_show() { + local proto=${1} + assert isset proto + + local subnet_id=${2} + assert isset subnet_id + + local level=${3} + isset level || level=0 + + local $(dhcpd_subnet_settings ${proto}) + + # Read in configuration settings. + dhcpd_subnet_read ${proto} ${subnet_id} + + cli_headline $(( ${level} + 1 )) \ + "DHCP${proto/ip/} subnet declaration #${subnet_id}" + cli_print_fmt1 $(( ${level} + 1 )) \ + "Subnet" "${ADDRESS}/${PREFIX}" + cli_space + + # Read the options. + local -A options + dhcpd_subnet_options_read ${proto} ${subnet_id} + + # Print the options if any. + if [ ${#options[*]} -gt 0 ]; then + cli_headline $(( ${level} + 2 )) "Options" + + local option + for option in $(dhcpd_subnet_options ${proto}); do + [ -n "${options[${option}]}" ] || continue + + cli_print_fmt1 $(( ${level} + 2 )) \ + "${option}" "${options[${option}]}" + done + cli_space + fi + + # Ranges. + cli_headline $(( ${level} + 2 )) "Ranges" + + local ranges=$(dhcpd_subnet_range_list ${proto} ${subnet_id}) + if isset ranges; then + local range_id $(dhcpd_subnet_range_settings ${proto}) + for range_id in ${ranges}; do + dhcpd_subnet_range_read ${proto} ${subnet_id} ${range_id} + + cli_print $(( ${level} + 2 )) \ + "#%d: %s - %s" ${range_id} ${START} ${END} + done + else + cli_print $(( ${level} + 2 )) "No ranges have been defined." + fi + + cli_space +} + +function cli_dhcpd_options() { + local proto=${1} + assert isset proto + shift + + local subnet_id=${1} + assert isset subnet_id + shift + + local valid_options=$(dhcpd_subnet_options ${proto}) + + local key val + while [ $# -gt 0 ]; do + case "${1}" in + *=*) + key=$(cli_get_key ${1}) + val=$(cli_get_val ${1}) + + dhcpd_subnet_option_set ${proto} ${subnet_id} ${key} ${val} + esac + done +} + +function cli_start() { + if cli_help_requested $@; then + cli_show_man network + exit ${EXIT_OK} + fi + + local zones=$(zones_get $@) + + local zone + for zone in ${zones}; do + zone_start ${zone} & + done + + wait # until everything is settled +} + +function cli_stop() { + if cli_help_requested $@; then + cli_show_man network + exit ${EXIT_OK} + fi + + local zones=$(zones_get $@) + + local zone + for zone in ${zones}; do + zone_stop ${zone} & + done + + wait # until everything is settled +} + +function cli_restart() { + if cli_help_requested $@; then + cli_show_man network + exit ${EXIT_OK} + fi + + cli_stop $@ + + # Give the system some time to calm down + sleep ${TIMEOUT_RESTART} + + cli_start $@ +} + +function cli_status() { + if cli_help_requested $@; then + cli_show_man network + exit ${EXIT_OK} + fi + + # When dumping status information, the debug + # mode clutters the console which is not what we want. + # Logging on the console is disabled for a short time. + local log_disable_stdout=${LOG_DISABLE_STDOUT} + LOG_DISABLE_STDOUT="true" + + local zones=$(zones_get $@) + + local zone + for zone in ${zones}; do + zone_status ${zone} + done + + # Reset logging. + LOG_DISABLE_STDOUT=${log_disable_stdout} +} + +function cli_reset() { + if cli_help_requested $@; then + cli_show_man network + exit ${EXIT_OK} + fi + + warning_log "Will reset the whole network configuration!!!" + + # Force mode is disabled by default + local force=0 + + while [ $# -gt 0 ]; do + case "${1}" in + --force|-f) + force=1 + ;; + esac + shift + done + + # If we are not running in force mode, we ask the user if he does know + # what he is doing. + if ! enabled force; then + if ! cli_yesno "Do you really want to reset the whole network configuration?"; then + exit ${EXIT_ERROR} + fi + fi + + local zone + for zone in $(zones_get --all); do + zone_remove ${zone} + done + + local port + for port in $(ports_get --all); do + port_remove ${port} + done + + # Flush all DNS servers. + dns_server_flush + + # Re-run the initialization functions + init_run + + exit ${EXIT_OK} +} + +# Help function: will show the default man page to the user. +# Optionally, there are two arguments taken, the type of hook +# and which hook should be shown. +function cli_help() { + local type=${1} + local what=${2} + + # Remove unknown types. + if ! listmatch ${type} zone port config; then + type="" + fi + + # If no arguments were given, we will show the default page. + if [ -z "${type}" ]; then + cli_show_man network + return ${EXIT_OK} + fi + + if ! hook_exists ${type} ${what}; then + error "Hook of type '${type}' and name '${what}' could not be found." + exit "${EXIT_ERROR}" + fi + + hook_exec ${type} ${what} help +} + +function cli_dns_server() { + if cli_help_requested $@; then + cli_show_man network-dns-server + exit ${EXIT_OK} + fi + + # Get the command. + local cmd=${1}; shift + if [ -z "${cmd}" ]; then + cli_show_man network-dns-server + exit ${EXIT_ERROR} + fi + + # Get the new server to process (if any). + local server=${1} + local priority=${2} + + case "${cmd}" in + list) + dns_server_list + exit ${EXIT_OK} + ;; + add) + if dns_server_exists ${server}; then + error "DNS server '${server}' already exists!" + exit ${EXIT_ERROR} + fi + + log INFO "Adding new DNS server: ${server}" + dns_server_add ${server} ${priority} + ;; + remove) + if ! dns_server_exists ${server}; then + error "DNS server '${server}' does not exist!" + exit ${EXIT_ERROR} + fi + + log INFO "Removing DNS server: ${server}" + dns_server_remove ${server} ${priority} + ;; + update) + # Just run the update afterwards. + ;; + *) + error "No such command: ${cmd}" + exit ${EXIT_ERROR} + esac + + # Update the local DNS configuration after changes have been made. + dns_generate_resolvconf + radvd_update + + exit ${EXIT_OK} +} + # Process the given action case "${action}" in init) init_run ;; - config|port|device|zone|start|stop|restart|status|reset) + config|hostname|port|device|zone|start|stop|restart|status|reset|route) cli_${action} $@ ;; + # DHCP server configuration (automatically detects which protocol to use). + dhcpv6|dhcpv4) + cli_dhcpd ${action/dhcp/ip} $@ + ;; + + # DNS server configuration. + dns-server) + cli_dns_server $@ + ;; + ""|help|--help|-h) - cli_usage root - exit ${EXIT_OK} + cli_help $@ ;; *) error "Invalid command given: ${action}" - cli_usage usage + cli_usage "network help" exit ${EXIT_CONF_ERROR} ;; esac + +exit ${EXIT_OK}