#!/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 . # # # ############################################################################### # Parse the command line while [ $# -gt 0 ]; do case "${1}" in -d|--debug) DEBUG=1 ;; *) action=${1} ;; esac shift [ -n "${action}" ] && break done . /usr/lib/network/functions 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="${COLOUR_GREEN}UP${COLOUR_NORMAL}" ;; ${EXIT_FALSE}) status="${COLOUR_RED}DOWN${COLOUR_NORMAL}" ;; 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 virtual devices. local virtuals=$(device_get_virtuals ${device}) if [ -n "${virtuals}" ]; then cli_headline 2 "Virtual devices" local virtual for virtual in ${virtuals}; do cli_print 2 "* %-6s - %s" "${virtual}" "$(device_get_address ${virtual})" 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 $@ ;; *) error "Unrecognized action: ${action}" cli_run_help network route exit ${EXIT_ERROR} ;; esac exit ${EXIT_OK} } 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() { if cli_help_requested $@; then cli_show_man network-dns exit ${EXIT_OK} fi # Get the command. local cmd=${1}; shift if [ -z "${cmd}" ]; then cli_show_man network-dns exit ${EXIT_ERROR} fi # Get the new server to process (if any). local server=${1} local priority=${2} case "${cmd}" in list) __dns_server_println "SERVER" "PRIORITY" dns_server_list exit ${EXIT_OK} ;; add) log INFO "Adding new DNS server: ${server}" dns_server_add ${server} ${priority} ;; remove) 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|hostname|port|device|zone|start|stop|restart|status|reset|dns|route) cli_${action} $@ ;; ""|help|--help|-h) cli_help $@ ;; *) error "Invalid command given: ${action}" cli_usage "network help" exit ${EXIT_CONF_ERROR} ;; esac exit ${EXIT_OK}