Vladimir Melnik

Just another WordPress site

How to find out where exactly the packet is being lost

It’s a pretty common occurrence when you have 2 hosts pinging each other and some packets are being lost. And sometimes you need to make sure, that the routing device in between of these host really receives a request, forwards this request to the target, receives the reply and forwards it back to the request’s initiator. If you’re lucky enough to run tcpdump on this intermediate device (if it runs some Unix-like OS, e.g. Linux or FreeBSD), you can wrap it to the script that will analyze each transit packet to find out what exactly is going wrong.

If you watch the tcpdump output with the naked eye, you’ll see the following pattern:

01:14:15.658173  In 08:60:6e:e7:a9:94 ethertype IPv4 (0x0800), length 76: 192.168.0.223 > 192.168.1.196: ICMP echo request, id 14, seq 23873, length 40
01:14:15.658187 Out 00:1b:21:1c:47:ad ethertype IPv4 (0x0800), length 76: 192.168.0.223 > 192.168.1.196: ICMP echo request, id 14, seq 23873, length 40
01:14:15.658397  In f4:6d:04:2a:67:56 ethertype IPv4 (0x0800), length 76: 192.168.1.196 > 192.168.0.223: ICMP echo reply, id 14, seq 23873, length 40
01:14:15.658409 Out 00:e0:81:74:0f:1b ethertype IPv4 (0x0800), length 76: 192.168.1.196 > 192.168.0.223: ICMP echo reply, id 14, seq 23873, length 40
01:14:16.673167  In 08:60:6e:e7:a9:94 ethertype IPv4 (0x0800), length 76: 192.168.0.223 > 192.168.1.196: ICMP echo request, id 14, seq 23874, length 40
01:14:16.673180 Out 00:1b:21:1c:47:ad ethertype IPv4 (0x0800), length 76: 192.168.0.223 > 192.168.1.196: ICMP echo request, id 14, seq 23874, length 40
01:14:16.673456  In f4:6d:04:2a:67:56 ethertype IPv4 (0x0800), length 76: 192.168.1.196 > 192.168.0.223: ICMP echo reply, id 14, seq 23874, length 40
01:14:16.673468 Out 00:e0:81:74:0f:1b ethertype IPv4 (0x0800), length 76: 192.168.1.196 > 192.168.0.223: ICMP echo reply, id 14, seq 23874, length 40
01:14:17.686607  In 08:60:6e:e7:a9:94 ethertype IPv4 (0x0800), length 76: 192.168.0.223 > 192.168.1.196: ICMP echo request, id 14, seq 23875, length 40
01:14:17.686620 Out 00:1b:21:1c:47:ad ethertype IPv4 (0x0800), length 76: 192.168.0.223 > 192.168.1.196: ICMP echo request, id 14, seq 23875, length 40
01:14:17.687496  In f4:6d:04:2a:67:56 ethertype IPv4 (0x0800), length 76: 192.168.1.196 > 192.168.0.223: ICMP echo reply, id 14, seq 23875, length 40
01:14:17.687514 Out 00:e0:81:74:0f:1b ethertype IPv4 (0x0800), length 76: 192.168.1.196 > 192.168.0.223: ICMP echo reply, id 14, seq 23875, length 40
01:14:18.700539  In 08:60:6e:e7:a9:94 ethertype IPv4 (0x0800), length 76: 192.168.0.223 > 192.168.1.196: ICMP echo request, id 14, seq 23876, length 40
01:14:18.700552 Out 00:1b:21:1c:47:ad ethertype IPv4 (0x0800), length 76: 192.168.0.223 > 192.168.1.196: ICMP echo request, id 14, seq 23876, length 40
01:14:18.700766  In f4:6d:04:2a:67:56 ethertype IPv4 (0x0800), length 76: 192.168.1.196 > 192.168.0.223: ICMP echo reply, id 14, seq 23876, length 40
01:14:18.700777 Out 00:e0:81:74:0f:1b ethertype IPv4 (0x0800), length 76: 192.168.1.196 > 192.168.0.223: ICMP echo reply, id 14, seq 23876, length 40

It’s easy to notice some obvious pattern in this dump, there are 4 obvious phases.

A request came:

01:14:15.658173  In 08:60:6e:e7:a9:94 ethertype IPv4 (0x0800), length 76: 192.168.0.223 > 192.168.1.196: ICMP echo request, id 14, seq 23873, length 40

The request gone:

01:14:15.658187 Out 00:1b:21:1c:47:ad ethertype IPv4 (0x0800), length 76: 192.168.0.223 > 192.168.1.196: ICMP echo request, id 14, seq 23873, length 40

The reply came:

01:14:15.658397  In f4:6d:04:2a:67:56 ethertype IPv4 (0x0800), length 76: 192.168.1.196 > 192.168.0.223: ICMP echo reply, id 14, seq 23873, length 40

The reply gone:

01:14:15.658409 Out 00:e0:81:74:0f:1b ethertype IPv4 (0x0800), length 76: 192.168.1.196 > 192.168.0.223: ICMP echo reply, id 14, seq 23873, length 40

So you can sit and watch the packets being received and transmitted, but it can be really boring, so you can run the following script:

#!/bin/bash

function warn {
        echo -e "$(date +"%F %T") $*" >&2
}

function die {
        warn "$*"
        exit 13
}

while getopts ":s:d:v" OPT; do
        case "${OPT}" in
                s)
                        SOURCE="${OPTARG}"
                        ;;
                d)
                        DESTINATION="${OPTARG}"
                        ;;
                v)
                        VERBOSE=1
                        ;;
                \?)
                        die "Invalid option: -${OPTARG}"
                        ;;
                \:)
                        die "Option -${OPTARG} requires an argument"
                        ;;
        esac
done
[[ -z "${SOURCE}"      ]] && die "The source address is undefined"
[[ -z "${DESTINATION}" ]] && die "The destination address is undefined"

NEXT_PHASE=0
NEXT_SEQ=0

tcpdump -l -n -i any -e "icmp and host ${SOURCE} and host ${DESTINATION}" 2>/dev/null |

        while :; do

                [[ "${VERBOSE}" -eq 1 ]] && echo -n ">${NEXT_PHASE}"

                read LINE

                INPUT=($(echo "${LINE}" | sed -n -r 's/^[0-9:\.]+  ?(In|Out) .+ ([0-9\.]+) > ([0-9\.]+): ICMP echo (request|reply), id [0-9]+, seq ([0-9]+).*, length [0-9]+$/\1 \2 \3 \4 \5/gp'))

                NEW_SEQ="${INPUT[4]}"

                case "${INPUT[3]}" in
                        'request')
                                NEW_PHASE=1
                                ([[ "${INPUT[1]}" == "${SOURCE}" ]] && [[ "${INPUT[2]}" == "${DESTINATION}" ]]) || continue 3
                                ;;
                        'reply')
                                NEW_PHASE=3
                                ([[ "${INPUT[2]}" == "${SOURCE}" ]] && [[ "${INPUT[1]}" == "${DESTINATION}" ]]) || continue 3
                                ;;
                        *)
                                die "(1) The following line looks strange:\n${LINE}"
                                ;;
                esac
                case "${INPUT[0]}" in
                        'In')
                                ;;
                        'Out')
                                NEW_PHASE=$((${NEW_PHASE} + 1))
                                ;;
                        *)
                                die "(2) The following line looks strange:\n${LINE}"
                                ;;
                esac

                [[ "${NEXT_PHASE}" -eq 0 ]] && NEXT_PHASE="${NEW_PHASE}"
                [[ "${NEXT_SEQ}"   -eq 0 ]] && NEXT_SEQ="${NEW_SEQ}"

                [[ "${NEXT_PHASE}" -ne "${NEW_PHASE}" ]] && warn "Wrong phase, expected ${NEXT_PHASE}, got ${NEW_PHASE}:\n${LINE}"
                [[ "${NEXT_SEQ}" -ne "${NEW_SEQ}" ]] && warn "Wrong seq, expected ${NEXT_SEQ}, got ${NEW_SEQ}:\n${LINE}"

                if [[ ${NEXT_PHASE} -eq 4 ]]; then
                        NEXT_PHASE=1
                        NEXT_SEQ=$((${NEXT_SEQ} + 1))
                else
                        NEXT_PHASE=$((${NEXT_PHASE} + 1))
                fi

        done

It reads the output of tcpdump and prints an alert message when the usual pattern gets broken. When some request or some reply is absent or the seq-number is unexpected, it will print something like that:

2016-06-14 23:37:51 Wrong seq, expected 18167, got 18168:
23:37:51.919246 Out 00:1b:21:1c:47:ad ethertype IPv4 (0x0800), length 76: 192.168.0.223 > 192.168.1.196: ICMP echo request, id 14, seq 18168, length 40

The latest version is available at GitHub: https://gist.github.com/anonymous/2e8b6883c93326de280124c077424cc6.

chebur

Ходоки

Бывает, чел вот, например, идёт, потом смотрит – куда-то не туда зашёл, думает, как выйти, а потом вспоминает, что, пока шёл, часто забывал, куда дойти хотел, а потому совсем другие пути выбирал, вот и пришёл не туда. Другой – оппа, оппа – и, куда ему было нужно, бодренько так добрался, не опоздал и даже не запылился особо. А иной помнил, куда идёт, знал, что идёт вовсе не туда, но топал вполне уверенно, потому что уж очень хотелось пойти и посмотреть, что там. Пришёл посмотреть, смотрел, смотрел, да там и ослеп, теперь так и стоит, куда пришёл.

Для прочих же давно изобретены велосипеды.

The 13th One (+ a bit of Hypermouse) [Mix]

‘Cause all work and no play makes Vlad a dull boy

How to test a TCP-connection

Sometimes it’s not enough to estimate the packet loss ratio only, but to make sure that a TCP-connections are stable. Run the “server” instance (sockping -m server -p 65513) on some host and run the “client” (sockping -m client -h 13.13.13.13 -p 65513) on another one, and the “client” will connect to the “server” and then it’ll be sending probe messages and expecting replies. If the TCP-session is broken, the “server” states it to STDERR.

#!/bin/bash

function log {
    echo $(date) ' >> ' $* >&2
}

function die {
    echo $* >&2
}

while getopts ":m:h:p:" OPT; do
    case "${OPT}" in
        m)
            MODE="${OPTARG}"
            ;;
        h)
            HOST="${OPTARG}"
            ;;
        p)
            PORT="${OPTARG}"
            ;;
        \?)
            die "Invalid option: -${OPTARG}"
            ;;
        🙂
            die "Option -${OPTARG} requires an argument."
            ;;
    esac
done

case "${MODE}" in

    client)
        [[ -z "${HOST}" ]] && die "Host isn't defined"
        [[ -z "${PORT}" ]] && die "Port isn't defined"
        socat TCP:${HOST}:${PORT} EXEC:"${0} -m client-ping",su-d=nobody
        ;;

    client-ping)
        PING=1
        while :; do
            # Sending ping
            echo -e "$(date +%s)\t${PING}"
            # Receiving pong
            read STRING
            # Checking latency
            TIME_NEW="$(date +%s)"
            if [[ ! -z "${TIME_OLD}" ]]; then
                LATENCY=$(( ${TIME_NEW} - ${TIME_OLD} ))
                if [[ "${LATENCY}" -gt 2 ]]; then
                    log "The latency is too high (${TIME_NEW} - ${TIME_OLD} = ${LATENCY})"
                fi
            fi
            TIME_OLD="${TIME_NEW}"
            # Checking sequence delta
            PONG="$(echo "${STRING}" | cut -f 2)"
            [[ -z ${PONG} ]] && die "Invalid reply: ${STRING}"
            STEP=$(( ${PONG} - ${PING} ))
            [[ "${STEP}" -ne 1 ]] && log "Unexpected sequence step (${PING} - ${PONG} = ${STEP})"
            PING=$(( ${PONG} + 1 ))
            # Sleeping
            sleep 1
        done
        ;;

    server)
        if [[ -z "${PORT}" ]]; then
            die "Port isn't defined"
        fi
        while : ; do
                socat TCP-LISTEN:${PORT},fork,su=nobody EXEC:"${0} -m server-ping"
                sleep 1
                log "Restarting"
        done
        ;;

    server-ping)
        log "${SOCAT_PEERADDR} connected"
        while :; do
            read STRING
            PING="$(echo "${STRING}" | cut -f 2)"
            [[ -z ${PING} ]] && die "Invalid request: ${STRING}"
            PONG=$(( ${PING} + 1 ))
            echo -e "$(date +%s)\t${PONG}"
            #
            [[ $(( ${PONG} % 3600 )) -eq 0 ]] && log "Sent the ${PONG}'th pong!"
        done
        ;;

    *)
        die "Invalid mode: ${MODE}"
        ;;

esac

Saved to Gist.

seagull

How other people affect our lives

What if people influence on each other much more than we tend to believe? Did you ever assume that some events in other people’s lives, some traits of their destinies can occasionaly exude on our own lifeways? What if the more we interact with certain people and the more impact they have on us, the more circumstances of their lives can recur in our own lives? And what if each person (even the ones we meet in early childhood) leave some imprint on our future lives? And what if it happens not because we’ve “learned” something from these people or intentionally “got” something from them, but just because the reality works this way, so we repeat even things that we consider as undesirable? What if we always inherit some random (are they really random?) things from their scenarios even if we don’t want that? What do you think?

How to check all the sensors (a Nagios plugin)

thermometer

Ever fancied a Nagios plugin to check all the sensors on the host without any hassle? Try this one, it collects all the sensors’ input values, compares it to their thresholds (the script collects threshold values from the system by itself). Then the plugin throws a warning when the rate of input value to the threshold value is 0.8 or more (actually you can change it by the -w option), also it yells about the critical state if the rate is equal or greater than 1 (of course, you can change it too by the -c option, although I wouldn’t suggest you to do that).

Oh, I almost forgot to add: you need to have lm_sensors utiluity installed.

#!/bin/bash

CODE_OK=0
CODE_UNKNOWN=1
CODE_WARNING=2
CODE_CRITICAL=3

WARNING_THRESHOLD="80%"
CRITICAL_THRESHOLD="100%"
DEBUG=0

while getopts ":C:S:c:w:dh" OPT; do
    case "${OPT}" in
        C)
            CHIP="${OPTARG}"
            ;;
        S)
            SENSORS="${OPTARG}"
            ;;
        c)
            CRITICAL_THRESHOLD="${OPTARG}"
            ;;
        w)
            WARNING_THRESHOLD="${OPTARG}"
            ;;
        d)
            DEBUG=1
            ;;
        h)
            cat <<__USAGE_END__
$0 [-C <chip>] [-S <sensors>] [-w <warn>] [-c <crit>] [-d] [-h]

    -C <chip>     - to read sensors on certain chip
    -S <sensors>  - to read sensors matching certain regexp
    -w <warning>  - warning rate threshold (80% by default)
    -c <critical> - critical rate threshild (100% by default)
    -d            - to print debug info
    -h            - you've just done it 🙂
__USAGE_END__
                >&2
            exit ${CODE_UNKNOWN}
            ;;
        \?)
            echo "Invalid option: -${OPTARG}, see -h" >&2
            exit ${CODE_UNKNOWN}
            ;;
        🙂
            echo "Option -${OPTARG} requires some argument, see -h" >&2
            exit ${CODE_UNKNOWN}
            ;;
    esac
done

if [ -z "${CHIP}" ]; then
    DATA=$(/bin/sensors -u)
else
    DATA=$(/bin/sensors -u "${CHIP}")
fi
if [ $? -ne 0 ]; then
    echo "Can't get sensors' data" >&2
    exit ${CODE_UNKNOWN}
fi

echo "${DATA}" | awk \
    -v CriticalT="${CRITICAL_THRESHOLD}" \
    -v WarningT="${WARNING_THRESHOLD}" \
    -v Sensors="${SENSORS}" \
    -v CodeOK="${CODE_OK}" \
    -v CodeUnknown="${CODE_UNKNOWN}" \
    -v CodeWarning="${CODE_WARNING}" \
    -v CodeCritical="${CODE_CRITICAL}" \
    -v Debug=${DEBUG} \
    '
function Croak(Sensor, Input, Threshold) {
    printf(\
        "%s sensor shows %0.3f whilst its threshold is %0.3f (%0.0f%)\n", \
        Sensor, Input, Threshold, Input / Threshold * 100 \
    )
}
function Finish(Sensor, Input, Threshold, Alarm) {
    if(Debug) {
        printf( \
            "Finishing the %s sensor: input is %0.3f threshold is %0.3f alarm flag is %0.3f\n", \
            Sensor, Input, Threshold, Alarm \
        )
    }
    if(length(Sensors)) {
        if(Sensor !~ Sensors) {
            return
        }
    }
    if(Alarm > 0) {
        printf("%s sensor in alarm state\n", Sensor)
        exit CodeCritical
    }
    if(match(CriticalT, /^([[:digit:]]+)%$/, matched)) {
        if ((length(Threshold) > 0) && (Input / Threshold * 100 >= matched[1])) {
            Croak(Sensor, Input, Threshold)
            exit CodeCritical
        }
    } else {
        if (Input >= CriticalT) {
            Croak(Sensor, Input, CriticalT)
            exit CodeCritical
        }
    }
    if(match(WarningT, /^([[:digit:]]+)%$/, matched)) {
        if ((length(Threshold) > 0) && (Input / Threshold * 100 >= matched[1])) {
            Croak(Sensor, Input, Threshold)
            exit CodeWarning
        }
    } else {
        if (Input >= WarningT) {
            Croak(Sensor, Input, WarningT)
            exit CodeWarning
        }
    }
}
// {
    if(match($0, /^([^:]+):$/, matched)) {
        SensorNew = matched[1]
        if(length(Sensor) > 0) {
            Finish(Sensor, Input, Threshold, Alarm)
        }
        Sensor = SensorNew
        Input = ""
        Threshold = ""
        Alarm = ""
    }
    if(match($0, /^[[:space:]]+([^:]+): ([0-9\.\-]+)$/, matched)) {
        Parameter = matched[1]
        Value = matched[2]
        if(Parameter ~ /_input$/) {
            Input = Value
        }
        if(Parameter ~ /_(max|crit|emergency)$/) {
            if (Value > Threshold) {
                Threshold = Value
            }
        }
        if(Parameter ~ /_alarm$/) {
            Alarm = Value
        }
    }
}
END {
    if(length(Sensor) > 0) {
        Finish(Sensor, Input, Threshold, Alarm)
    }
}'

STATUS="${?}"
if [ "${STATUS}" -lt 4 ]; then
    exit "${STATUS}"
else
    exit "${CODE_UNKNOWN}"
fi

Here are some examples:

check_all_sensors.sh
This command will check each sensor on each chip. It will raise the critical status when the input value is equal or greater than 100% of the threshold value. If the input value is greater or equal to 80% of the threshold value, the warning state will be raised. All threshold values are being got from the system.

check_all_sensors.sh -c 90% -w 50%
It’s almost the same, but the critical rate is 90% and the warning rate is 50%.

check_all_sensors.sh -C zaloopa -S '/^Temperature [0-9]+$/' -c 90 -w 75
Only temperature sensors on the zaloopa chip will be checked. The critical status will be raised when the absolute input value is greater or equal to 90 degrees. If it’s equal or greater than 75 degrees, the warning state will be thrown.

Also saved it to Gist.

How to determine on which hop your datagrams are being lost without the mtr utility

Sometimes you need to detect which host loses IP-packets being sent by you. It’s good when you can use the mtr utility, but what to do if you can’t install it?

Here’s a short and very simple script that could help you with that.

#/bin/bash

HST="8.8.8.8"
CNT="100"
DIR="$(mktemp -d /tmp/ping_XXXXXXXX)"

echo "Results will be stored to the ${DIR} directory"

for HOP in $(traceroute -n "${HST}" | sed -nr 's/^[[:space:]]*([[:digit:]]+)[[:space:]]+([[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3})[[:space:]]+.*$/\1:\2/gp'); do
    IFS_OLD="${IFS}"; IFS=":"; read -a ARR <<< "${HOP}"; IFS="${IFS_OLD}"
    ping -c "${CNT}" ${ARR[1]}" > "${DIR}/pingtrace_${ARR[0]}_${ARR[1]}" &
done

echo -n "Waiting for ${CNT} packets to be sent..."; sleep "$((CNT+3))"; echo "OK!"
grep "transmitted" "${DIR}"/*

It traces the route to the destination and then run a bunch of simultaneous ping commands to all hosts found.

Also published to Gist.

IP-address Round-Robin for Postifx

Here’s a short and pretty self-desctriptive recipe to make your Postfix to send outgoing messages from different IP-addresses switching them on a round-robin basis.

First of all, we’ll need the list of IP-addresses in our roundabout, let’s put them to the /etc/postfix/roundabout file:

172.16.13.1
172.16.13.2
172.16.13.3
172.16.13.4

Then we’ll need the script to add IP-address aliases to our network interface. Surely, you can add them to the operating system configuration, but I’d suggest you to keep them all to the same /etc/postfix/roundabout file, so let’s put it to the /root/bin/roundabout_aliases.sh file:

#!/bin/bash

PATH=/bin:/sbin

ROUNDABOUT_SPOOL=/etc/postfix/roundabout
DEVICE=eth0

if [ ! -r "${ROUNDABOUT_SPOOL}" ]; then
        echo "Can't read Roundabout configuration (${ROUNDABOUT_SPOOL})" >&2
        exit 13
fi

COUNT=0
FOUND=0

ADDRESSES=($(ip addr show "${DEVICE}" | sed -r -n "s/^[[:space:]]*inet ([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})\/([0-9]{1,2}).*$/\1/gp"))

while read LINE; do

        ADDRESS=$(echo "${LINE}" | sed -nr "s/^[[:space:]]*([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})[[:space:]]*\$/\1/pi")
        if [ -z "${ADDRESS}" ]; then
                continue
        fi

        for TEST in ${ADDRESSES[@]}; do
                if [ "${TEST}" = "${ADDRESS}" ]; then
                        continue 2;
                fi
        done

        ip address add "${ADDRESS}" dev "${DEVICE}"

done < "${ROUNDABOUT_SPOOL}"

If we want this script to be invoked automatically when the network interface starts, let’s create or modify the /sbin/ifup-local script (if we have a CentOS/RedHat-based system):

#!/bin/sh

if [ "$1" -eq "eth0" ]; then
    /root/bin/roundabout_aliases.sh
fi

And now, the last, but not ever least, let’s implement the little script to change the smtp_bind_address value in our /etc/postfix/postfix.conf configuration. Let’s call it /root/bin/roundabout-postfix.sh:

#!/bin/bash

PATH=/bin:/sbin:/usr/sbin

ROUNDABOUT_SPOOL=/etc/postfix/roundabout
POSTFIX_CONFIG=/etc/postfix/main.cf

if [ ! -r "${POSTFIX_CONFIG}" ]; then
        echo "Can't read Postfix configuration (${POSTFIX_CONFIG})" >&2
        exit 13
fi

SMTP_BIND_ADDRESS=$(cat "${POSTFIX_CONFIG}" | sed -nr "s/^[[:space:]]*smtp_bind_address[[:space:]]*=[[:space:]]*([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})[[:space:]]*\$/\1/pi")

if [ -z "${SMTP_BIND_ADDRESS}" ]; then
        echo "Can't determine the current IP-address" >&2
        exit 13
fi

if [ ! -r "${ROUNDABOUT_SPOOL}" ]; then
        echo "Can't read Roundabout configuration (${ROUNDABOUT_SPOOL})" >&2
        exit 13
fi

COUNT=0
FOUND=0

while read LINE; do

        ADDRESS=$(echo "${LINE}" | sed -nr "s/^[[:space:]]*([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})[[:space:]]*\$/\1/pi")
        if [ -z "${ADDRESS}" ]; then
                continue
        fi

        COUNT=$((COUNT+1))
        if [ "${COUNT}" -eq 1 ]; then
                ADDRESS1="${ADDRESS}"
        fi

        if [ "${FOUND}" -eq 1 ]; then
                SMTP_BIND_ADDRESS_NEW="${LINE}"
                break
        fi

        if [ "${LINE}" = "${SMTP_BIND_ADDRESS}" ]; then
                FOUND=1
        fi

done < "${ROUNDABOUT_SPOOL}"

if [ -z "${ADDRESS1}" ]; then
        echo "There are no entries in the Roundabout spool" >&2
        exit 13
fi

if [ -z "${SMTP_BIND_ADDRESS_NEW}" ]; then
        SMTP_BIND_ADDRESS_NEW="${ADDRESS1}"
fi

sed -r -i -e "s/^[[:space:]]*smtp_bind_address[[:space:]]*=[[:space:]]*([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})[[:space:]]*\$/smtp_bind_address = ${SMTP_BIND_ADDRESS_NEW}/i" "${POSTFIX_CONFIG}"

if [ "${?}" -ne 0 ]; then
        echo "Something went wrong :-(" >&2
        exit 13
fi

postfix reload >/dev/null 2>&1

if [ "${?}" -ne 0 ]; then
        echo "Something went wrong :-(" >&2
        exit 13
fi

You can run this script by cron or when certain event happens (e.g., when the current IP-address has been blacklisted).

And don’t forget to add something like smtp_bind_address = 0.0.0.0 to the /etc/postfix/main.cf file before to run this script for the first time, in other case it won’t find the IP-address to be changed! 🙂

Some sassy fella

Did you foresaw your future life when you were younger?

At some point you may start to realize that you had foreseen all your furure life and all future events in the world around you quite a long time ago. Were there some dreams or some unexpected thoughts, even some past things that you could now consider as pretty obvious signs – all these things were quite obvious, so you somehow knew that your life will go this way or that one.

]Are you familiar with that feeling? If yes – what do you think, doesn’t that mean that you’ve made the world around you by your imagination?

Living my music

I really love music! I love to listen music, to feel it, to compose my tunes and to play them. I’m pretty sure that principles of musical harmonies, chords and progressions can be applied to varions things in the universe, because the world itself seem to be organized by the same rules. Surely, I’m not an expert in physics and mathematics, but you don’t need to be a PhD to see the obvious. 🙂

I decided to try an odd experiment. I’ve divided the week to 12 equal chunks complied to 12 halftones, so one week is treated as a full octave. It could look like that:

octave-week-blank

Then I’m going to “play” various chords progressions, just by doing certain things at certain hours corresponding to certain tones. For example, “playing” a C-chord means doing some things in the following periods:

  • from 00:00 till 14:00 of Monday,
  • from 08:00 till 22:00 of Wednesday,
  • from 02:00 till 16:00 of Friday.

octave-week-C-chord

On the next week I’ll “play” some other chord, for example, an Am-chord. Then goes an F-chord. And then – a G-chord. So, some progression will be “played”.

What it gives? I don’t know yet! 🙂 I need to try and then I could tell about results.

What exactly I’ll do at these hours? I’m going to decide it. But, just kind of wondering, what would YOU do at some *magic* time periods if you knew they’re *magic*?

Thank you!