是否可以在没有任何响应的情况下关闭http连接?

时间:2012-12-30 19:08:40

标签: apache security connection

如何在没有任何响应的情况下使用apache关闭http连接?如果我发现请求是黑客攻击,我想关闭连接而不对请求做出任何响应。

现在我有类似的东西:

GET / HTTP/1.0
User-Agent: Hacking-Tool

HTTP/1.1 403 Forbidden
Date: Sun, 30 Dec 2012 19:00:56 GMT
Server: Apache/2.2.0 (Linux/SUSE) mod_ssl/2.2.0 PHP/5.1.2 SVN/1.4.6
Content-Length: 13
Connection: close
Content-Type: plain/text; charset=utf-8

Stop hacking!

我怎样才能简单地关闭连接,以便黑客无法猜测我正在运行Linux系统。我知道我可以减少服务器签名,这无关紧要。

2 个答案:

答案 0 :(得分:1)

你问了两个问题,试着避免这个问题:)。

首先,您要防止OS / app指纹识别。你可以通过删除服务器头,并更改apache错误页面来做到这一点......仍然有一些概率攻击者可以猜测你的操作系统和http服务器。您可以使用Apache Mod Security来帮助自己。

其次是在应用程序级别,逻辑执行(您的应用程序确定请求是否是黑客攻击尝试)之后没有正确的http响应标头的情况下关闭连接。在PHP中我认为你不能这样做。执行解析器时,我认为响应已经由apache准备,如果解析器没有返回任何空响应或者错误响应将由apache本身发送。我认为如果你使用一些标题过滤,只返回普通字符串“检测到黑客企图。管理员已收到通知。可能会出现法律后果。”你会很好地吓唬一些脚本小子。

P.S。我好奇你的应用程序能够检测到什么黑客攻击?这是CSRF令牌验证吗?这种简单的未经过身份验证的访问尝试或其他形式的授权检查吗?还是你开发的一些安全机制?

答案 1 :(得分:1)

可以关闭http连接而无需向客户端发送任何响应。但是相当投入。不必那么难。

IP表规则:

iptables -t raw -I PREROUTING 1 -m recent --rsource --mask 255.255.255.0 --update --seconds 259200 --name DYN_DROP_IPv4 -j DROP
iptables -t raw -I OUTPUT 1 -m recent --rsource --mask 255.255.255.0 --update --seconds 259200 --name DYN_DROP_IPv4 -j DROP

ip6tables -t raw -I PREROUTING 1 -m recent --rsource --mask ffff:ffff:ffff:ffff:0:0:0:0 --update --seconds 259200 --name DYN_DROP_IPv6 -j DROP
ip6tables -t raw -I OUTPUT 1 -m recent --rsource --mask ffff:ffff:ffff:ffff:0:0:0:0 --update --seconds 259200 --name DYN_DROP_IPv6 -j DROP

httpd配置重写规则以运行脚本:

# The network mask must be the same as the iptables rule mask
Define DynDropIP_QueryString '\
?action=+\
&addr=%{REMOTE_ADDR}\
&port=%{REMOTE_PORT}\
&mask_ipv4=255.255.255.0\
&mask_ipv6=ffff:ffff:ffff:ffff:0:0:0:0\
&remote_host=%{REMOTE_HOST}\
&server_name=%{SERVER_NAME}\
&server_port=%{SERVER_PORT}\
&request_method=%{REQUEST_METHOD}\
&request_uri=%{REQUEST_URI}\
&http_user_agent=%{HTTP_USER_AGENT}\
'

Define BAD_REQUESTS_REGEX '\
^/./|\
^/\.|\
^/[0-9]+|\
^/admin|\
'

Define BAD_BOTS_REGEX '\
^.$|\
11A465|\
Ahrefs|\
ArchiveBot|\
AspiegelBot|\
Baiduspider|\
'

RewriteCond %{REQUEST_URI} ${BAD_REQUESTS_REGEX} [NC,OR]
RewriteCond %{HTTP_USER_AGENT} ${BAD_BOTS_REGEX} [NC]

# Dynamic Drop IP Script
RewriteRule ^.* /cgi-bin/DynDropIP${DynDropIP_QueryString} [PT,E=dontlog,L,END]

UnDefine DynDropIP_QueryString
UnDefine BAD_REQUESTS_REGEX
UnDefine BAD_BOTS_REGEX

cgi-bin/DynDropIP

#!/bin/sh

main() {
    # Pass query string trough to the named pipe (FIFO file) daemon; Redirect stderr to bit bucket
    fifo_dir='/var/run/DynDropIP/'
    fifo_file='xt_recent_fifo'

    if [[ -p "${fifo_dir}${fifo_file}" ]]; then
        printf "%s\n" "${QUERY_STRING}" 1>"${fifo_dir}${fifo_file}" 2>/dev/null
    fi

    response
}


response() {
    # Allow a few seconds for the firewall to be updated before responding (desire firewall to block the response)
    sleep 3

    # Set the HTTP response headers (404 and content type)
    # end of HTTP headers (empty line i.e. 2nd consecutive line feed)
    # Send 404 error page (duplicate of Apache 2.4.6 default 404 page (en))
    printf "%s\n%s\n\n%s\n" \
    "Status: 404 Not Found" \
    "Content-type: text/html; charset=iso-8859-1" \
"\
<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL ${REQUEST_URI} was not found on this server.</p>
</body></html>\
"
}


main

/usr/local/libexec/DynDropIP/xt_recent_fifo.sh
(运行此脚本以启动fifo和守护程序)

#!/bin/bash

fifo_dir='/var/run/DynDropIP/'
fifo_file='xt_recent_fifo'
daemon='/usr/local/libexec/DynDropIP/xt_recent_fifo_daemon.sh'

# Prep and clean first

# If fifo dir is not a dir remove and make dir
if [[ ! -d "${fifo_dir}" ]]; then
    rm -f "${fifo_dir}"
    mkdir -p "${fifo_dir}"
fi

# If fifo file exists remove
[ -a "${fifo_dir}${fifo_file}" ] || \
[ -e "${fifo_dir}${fifo_file}" ] || \
[ -f "${fifo_dir}${fifo_file}" ] || \
[ -h "${fifo_dir}${fifo_file}" ] || \
[ -p "${fifo_dir}${fifo_file}" ] && \
rm -f "${fifo_dir}${fifo_file}"

mkfifo -m 666 "${fifo_dir}${fifo_file}"

# For SELinux - Allow apache user to write to the fifo
chcon -t httpd_sys_rw_content_t "${fifo_dir}${fifo_file}"

tail -f "${fifo_dir}${fifo_file}" | "${daemon}" &

/usr/local/libexec/DynDropIP/xt_recent_fifo_daemon.sh

#!/bin/bash

main() {
    # Initialize IP address regex pattern vars
    IP_RegEx

    # Expected query string parameters: action (+/-), addr, port, mask_ipv4, mask_ipv6
    while read QUERY_STRING
    do
        # Parse the query string into associative array
        while IFS='=' read -r -d '&' key value && [[ -n "$key" ]]; do
            declare $key="$value"
        done <<<"${QUERY_STRING}&"

        if validate; then
            if process_address; then
                update_iptables
                logit
#               response
                destroy_tcp_socket
            fi
        fi
    done < "${1:-/dev/stdin}"
}


# Validate action, address and mask parameters
validate() {
    # Verify action parameter
    if [[ "${action}" != "+" && "${action}" != "-" ]]; then
        return 1    # failed: invalid action
    fi

    # Verify address and mask, set ip version if okay
    if [[ "${addr}" =~ ^${IPV4ADDR}$ && "${mask_ipv4}" =~ ^${IPV4ADDR}$ ]]; then
        ipv=4
    elif [[ "${addr}" =~ ^${IPV6ADDR}$ && "${mask_ipv6}" =~ ^${IPV6ADDR}$ ]]; then
        ipv=6
    else
        return 2    # failed: invalid address or network mask
    fi
}


# Process IPvN address
process_address() {
    if [[ $ipv -eq 4 ]]; then
        ipv4_network_mask
        if ! [[ "${maddr}" =~ ^${IPV4ADDR}$ ]]; then
            return 4    # failed: invalid masked ipv4 address
        fi
    elif [[ $ipv -eq 6 ]]; then
        ipv6_expand_address
        ipv6_native_notation
        ipv6_network_mask
        if ! [[ "${maddr}" =~ ^${IPV6ADDR}$ ]]; then
            return 6    # failed: invalid masked ipv6 address
        fi
    fi
}


# Compress IPv6 address (retain IPv4 dotted decimal or IPv6 native notation)
compress_address() {
    if [[ $addr =~ ^((${IPV6SEG}:){6})((${IPV6SEG}:${IPV6SEG})|(${IPV4ADDR}))$ ]]; then
        local IPv6_Segments IPv4_Segments pattern

        IPv6_Segments=${BASH_REMATCH[1]}${BASH_REMATCH[4]}
        IPv4_Segments=${BASH_REMATCH[5]}

        # Suppress hextet leading zeros; Three passes to get each of three
        IPv6_Segments=${IPv6_Segments//:0/:} && IPv6_Segments=${IPv6_Segments//:0/:} && IPv6_Segments=${IPv6_Segments//:0/:}

        # Reconstitute empty hextets with single zero; Two passes to get every other one
        IPv6_Segments=${IPv6_Segments//::/:0:} && IPv6_Segments=${IPv6_Segments//::/:0:}

        # First hextet special cases (0:)
        [[ $IPv6_Segments =~ ^0*([[:xdigit:]]+)(.*) ]] && IPv6_Segments="${BASH_REMATCH[1]}${BASH_REMATCH[2]}"

        # Last hextet special cases (:0, only if not followed by IPv4 segment)
        [[ $IPv6_Segments =~ [^:]:$ && -z $IPv4_Segments ]] && IPv6_Segments=$IPv6_Segments'0'

        # Compress longest contiguous hextets of zero to "::" (leftmost tiebreaker).
        for (( i=7; $i>=1; i-- ))
        do
            pattern=''
            for (( j=0; $j<$i; j++ ))
            do
                pattern+=':0'
            done

            # Compress at beginning
            [[ $IPv6_Segments =~ ^0$pattern ]] && IPv6_Segments=${IPv6_Segments/0$pattern/::} && break

            # Compress in the middle or at end
            [[ $IPv6_Segments =~ $pattern:0 ]] && IPv6_Segments=${IPv6_Segments/$pattern:0/::} && break

        done

        # Put address together and remove extra triple colons
        addr=$IPv6_Segments$IPv4_Segments
        addr=${addr/:::/::}
    fi
}


# Expand IPv6 Address (retain dotted decimal or native notation)
ipv6_expand_address() {
    local hextests num_colons additional_hextets

    # Number of hextets in an expanded IPv6 address (native notation)
    hextets=8

    # How many colons in address
    num_colons=${addr//[^:]/}
    num_colons=${#num_colons}

    # Is address IPv4 dotted decimal notation
    [[ $addr =~ :${IPV4ADDR}$ ]] && hextets=$((hextets-1))      # ::ffff:0:0/96, ::ffff:0:0:0/96, 64:ff9b::/96

    # Fix up beginning and end
    [[ $addr =~ ^:: ]] && addr='0'$addr
    [[ $addr =~ ::$ ]] && addr=$addr'0'

    # Create additional hextets
    additional_hextets=':'
    for (( i=$num_colons; $i<$hextets; i++ ))
    do
        additional_hextets+='0:'
    done

    # Insert additional hextets (replace ::)
    addr=${addr/::/$additional_hextets}
}


# Convert from IPv4 dotted decimal to IPv6 native notation (retain compressed / expanded)
ipv6_native_notation() {
    local expanded_flag
    # Ensure working with an expanded address
    [[ $addr =~ :: ]] && ipv6_expand_address && expanded_flag=1

    # Is address IPv4 dotted decimal notation
    if [[ $addr =~ ^(.*:)(${IPV4ADDR})$ ]]; then
        local IPv6_Segments IPv4_Segments
        local s1 s2 s3 s4 s1s2 s3s4

        IFS=. read -r s1 s2 s3 s4 <<< ${BASH_REMATCH[2]}    # IPv4 Segments 1, 2, 3, & 4

        s1s2=$(( ($s1 * 0x100) + $s2 ))                     # Hextet 7
        s3s4=$(( ($s3 * 0x100) + $s4 ))                     # Hextet 8

        IPv6_Segments=${BASH_REMATCH[1]}                    # Hextets 1, 2, 3, 4, 5, 6
        IPv4_Segments=$( printf "%x:%x" "$s1s2" "$s3s4" )   # As Hextets 7 & 8

        # Return converted native notation address (expanded)
        if [[ -n $IPv6_Segments && -n $IPv4_Segments ]]; then
            addr=$IPv6_Segments$IPv4_Segments
        fi
    fi

    # Revert expansion
    [[ $expanded_flag -eq 1 ]] && compress_address
}


# Convert from IPv6 native to IPv4 dotted decimal notation (retain compressed / expanded)
ipv6_dotted_decimal_notation() {
    local expanded_flag
    # Ensure working with an expanded address
    [[ $addr =~ :: ]] && ipv6_expand_address && expanded_flag=1

    # Is address IPv6 native notation
    if [[ $addr =~ ^(.*:)(${IPV6SEG}:${IPV6SEG})$ ]]; then
        local IPv6_Segments IPv4_Segments
        local s1 s2 UB LB

        IFS=: read -r s1 s2 <<< ${BASH_REMATCH[2]}          # IPv6 Segments 7 & 8

        UB=$((0xFF00))                                      # Upper Byte mask
        LB=$((0x00FF))                                      # Lower Byte mask

        IPv6_Segments=${BASH_REMATCH[1]}                    # Hextets 1, 2, 3, 4, 5, 6
        IPv4_Segments=$(((16#$s1 & $UB) / $LB)).$((16#$s1 & $LB)).$(((16#$s2 & $UB) / $LB)).$((16#$s2 & $LB))

        # Return converted dotted decimal notation address (expanded)
        if [[ -n $IPv6_Segments && -n $IPv4_Segments ]]; then
            addr=$IPv6_Segments$IPv4_Segments
        fi
    fi

    # Revert expansion
    [[ $expanded_flag -eq 1 ]] && compress_address
}


# Apply IPv4 network mask
ipv4_network_mask() {
    local s1 s2 s3 s4
    local m1 m2 m3 m4
    mask=$mask_ipv4     # Mask is also used in logit

    IFS=. read -r s1 s2 s3 s4 <<< $addr
    IFS=. read -r m1 m2 m3 m4 <<< $mask

    maddr="$((s1 & m1)).$((s2 & m2)).$((s3 & m3)).$((s4 & m4))"
}


# Apply IPv6 network mask
ipv6_network_mask() {
    local s1 s2 s3 s4 s5 s6 s7 s8
    local m1 m2 m3 m4 m5 m6 m7 m8
    mask=$mask_ipv6     # Mask is also used in logit

    IFS=: read -r s1 s2 s3 s4 s5 s6 s7 s8 <<< $addr
    IFS=: read -r m1 m2 m3 m4 m5 m6 m7 m8 <<< $mask

    maddr=$( \
    printf "%x:%x:%x:%x:%x:%x:%x:%x" \
    "$((0x$s1 & 0x$m1))" "$((0x$s2 & 0x$m2))" "$((0x$s3 & 0x$m3))" "$((0x$s4 & 0x$m4))" \
    "$((0x$s5 & 0x$m5))" "$((0x$s6 & 0x$m6))" "$((0x$s7 & 0x$m7))" "$((0x$s8 & 0x$m8))" \
    )
}


# Update table
update_iptables() {
    # Add/Remove validated address to/from the xt_recent table (action parameter +/- determines add/remove)
    # Redirect both stdout & stderr to null device so as not to inadvertently provide it to web user
    if [[ -n $action && -n $maddr && -n $ipv ]]; then
        printf "%s%s" $action $maddr 2>/dev/null \
        |/usr/bin/tee /proc/net/xt_recent/DYN_DROP_IPv$ipv \
        1>/dev/null 2>/dev/null
    fi
}


# Log entry
logit() {
    local log_dir='/var/log/iptables/DYN_DROP_IP/'
    local log_file='DYN_DROP_IPv'$ipv'.log'

    mkdir -p "$log_dir"

    # Address field width padding (string length, field width, pad chr/str, pad chr/str width)
    local field_width=0
    [[ $ipv -eq 4 ]] && field_width=15
    [[ $ipv -eq 6 ]] && field_width=39

    local  apad=$( logit_pad ${#addr}  $field_width '   ' 4 )
    local  mpad=$( logit_pad ${#mask}  $field_width '   ' 4 )
    local mapad=$( logit_pad ${#maddr} $field_width '   ' 4 )

    # Write log entry
    printf '%s  %s  %s  %s  %s  %s  %s  %s  %s  %s  %s  %s\n' \
    "$( date +'%Y-%m-%d %H:%M:%S %a' )" \
    "$ipv" \
    "$action" \
    "$addr$apad" \
    "$maddr$mapad" \
    "$mask$mpad" \
    "$remote_host" \
    "$server_name" \
    "$server_port" \
    "$request_method" \
    "$request_uri" \
    "$http_user_agent" \
    >> "$log_dir$log_file"

#   # Truncate to last 200 entries (skip header row)
#
#   if [[ $ipv -eq 4 ]]; then
#       local log_header='Date       Time     Day   IPv Action  IP Address  Blocked Network Network Mask    Client  Web Site    Scheme  Method  URI User Agent'
#   elif [[ $ipv -eq 6 ]]; then
#       local log_header='Date       Time     Day   IPv Action      IP Address                          Blocked Network                         Network Mask                            Client  Web Site    Scheme  Method  URI User Agent'
#   fi
#
#   printf '%s\n%s\n' \
#   "$log_header" \
#   "$(tail -n +2 $log_dir$log_file | tail -n -200)" \
#   > "$log_dir$log_file"
}


# Field width padding
logit_pad() {
    local str_length=$1
    local field_width=$2
    local pad_chr=$3
    local pad_chr_width=$4  # e.g. tab width

    local pad_length=$(( ($field_width - $str_length)  / $pad_chr_width ))

    local pad_string=''
    for (( i=0; $i<$pad_length; i++ ))
    do
        pad_string+=$pad_chr
    done

    printf "%s" "$pad_string"
}    


IP_RegEx() {
    # IPv4 Regular Expressions
    IPV4SEG='(25[0-5]|(2[0-4]|1[0-9]|[1-9])?[0-9])'         # doted decimal notation; no leading 0 (octal) or 0x (hexadecimal)
    IPV4ADDR='(('${IPV4SEG}'\.){3,3}('${IPV4SEG}'){1,1})'
    IPV4CIDR='(3[0-2]|[12]?[0-9])'


    # IPv6 Regular Expressions
    IPV6SEG='[0-9a-fA-F]{1,4}'                              # colon hextet notation; leading 0 permitted

    IPV6SEG8='('${IPV6SEG}':){7,7}('${IPV6SEG}'){1,1}'      # 1:2:3:4:5:6:7:8
    IPV6SEG7='('${IPV6SEG}':){1,7}(:''){1,1}'               # 1::                                 1:2:3:4:5:6:7::
    IPV6SEG6='('${IPV6SEG}':){1,6}(:'${IPV6SEG}'){1,1}'     # 1::8               1:2:3:4:5:6::8   1:2:3:4:5:6::8
    IPV6SEG5='('${IPV6SEG}':){1,5}(:'${IPV6SEG}'){1,2}'     # 1::7:8             1:2:3:4:5::7:8   1:2:3:4:5::8
    IPV6SEG4='('${IPV6SEG}':){1,4}(:'${IPV6SEG}'){1,3}'     # 1::6:7:8           1:2:3:4::6:7:8   1:2:3:4::8
    IPV6SEG3='('${IPV6SEG}':){1,3}(:'${IPV6SEG}'){1,4}'     # 1::5:6:7:8         1:2:3::5:6:7:8   1:2:3::8
    IPV6SEG2='('${IPV6SEG}':){1,2}(:'${IPV6SEG}'){1,5}'     # 1::4:5:6:7:8       1:2::4:5:6:7:8   1:2::8
    IPV6SEG1='('${IPV6SEG}':){1,1}(:'${IPV6SEG}'){1,6}'     # 1::3:4:5:6:7:8     1::3:4:5:6:7:8   1::8

    IPV6SEG0=':((:'${IPV6SEG}'){1,7}|:)'                    #  ::2:3:4:5:6:7:8    ::2:3:4:5:6:7:8  ::8       ::

    IPV6LLZI='[fF][eE]80:(:'${IPV6SEG}'){0,4}%[0-9a-zA-Z]{1,}'  # fe80::7:8%eth0     fe80::7:8%1  (link-local IPv6 addresses with zone index)

    IPV6V4MAP='(::|(0{1,4}:){5})[fF]{4}:'${IPV4ADDR}        # ::ffff:d.d.d.d        (::ffff:0:0/96 IPv4-mapped IPv6 addresses)
    IPV6V4TRN='(::|(0{1,4}:){4})[fF]{4}:0{1,4}:'${IPV4ADDR} # ::ffff:0:d.d.d.d      (::ffff:0:0:0/96 IPv4-translated addresses)
    IPV6V4CMP='(::|(0:){6})'${IPV4ADDR}                     # ::d.d.d.d             (IPv4-compatible (0::/96 deprecated by RFC4291))
#   IPV6V4TRN='::([fF]{4}(:0{1,4}){0,1}:){0,1}'${IPV4ADDR}  # ::d.d.d.d  ::ffff:d.d.d.d  ::ffff:0:d.d.d.d   (IPv4-mapped IPv6 addresses and IPv4-translated addresses))

    IPV6V4AMP='64:[fF]{2}9b:(:|(0{1,4}:){4})'${IPV4ADDR}    # 64:ff9b::d.d.d.d      (64:ff9b::/96 IPv4 translation addresses (algorithmic mapping RFC6052))
    IPV6V4LUT='64:[fF]{2}9b:1:(:|(0{1,4}:){3})'${IPV4ADDR}  # 64:ff9b:1::d.d.d.d    (64:ff9b:1::/48 Local-Use IPv4/IPv6 Translation RFC8215)
#   IPV6V4EMB='('${IPV6SEG}':){1,4}:'${IPV4ADDR}            # 2001:db8:3:4::d.d.d.d 64:ff9b::d.d.d.d (IPv4-Embedded IPv6 Address)

    IPV6ADDR='('\
'('${IPV6SEG8}')|('${IPV6SEG7}')|('${IPV6SEG6}')|('${IPV6SEG5}')|('${IPV6SEG4}')|('${IPV6SEG3}')|('${IPV6SEG2}')|('${IPV6SEG1}')|('${IPV6SEG0}')|'\
'('${IPV6LLZI}')|('${IPV6V4MAP}')|('${IPV6V4TRN}')|('${IPV6V4CMP}')|('${IPV6V4AMP}')|('${IPV6V4LUT}')'\
')'

    IPV6CIDR='(12[0-8]|(1[01]|[1-9])?[0-9])'

    PORT='([0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])'
}


response() {
    # Allow a few seconds for the firewall to be updated before responding (desire firewall to block the response)
    sleep 3

    # Set the HTTP response headers (404 and content type)
    # end of HTTP headers (empty line i.e. 2nd consecutive line feed)
    # Send 404 error page (duplicate of Apache 2.4.6 default 404 page (en))
    printf "%s\n%s\n\n%s\n" \
    "Status: 404 Not Found" \
    "Content-type: text/html; charset=iso-8859-1" \
"\
<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL ${REQUEST_URI} was not found on this server.</p>
</body></html>\
"
}


# On linux kernel >= 4.9 you can use the ss command from iproute2 with key -K
# ss -K dst 192.168.1.214 dport = 49029
# the kernel has to be compiled with CONFIG_INET_DIAG_DESTROY option enabled.
destroy_tcp_socket() {
#   if [[ "${port}" =~ ^${PORT}$ ]]; then           # Strictly Regex method

#   local -i port="10#${port}" 2> /dev/null         # Convert to integer method
#   if [[ $port -ge 1 && $port -le 65535 ]]; then

    # Is integer between 1 and 65535 (inclusive)
    local int_regex='^[0-9]+$'
    if [[ "$port" =~ $int_regex && $port -ge 1 && $port -le 65535 ]]; then
#       ss -K dst $addr dport = $port
        ss -K dst $addr:$port \
        1> /dev/null 2> /dev/null
    fi
}


main