Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using SSL with Bash's /dev/tcp

Tags:

bash

tcp

ssl

I just wrote an IRC bot in bash (I know, I know). It does everything I need it to (SASL auth, resolves links, etc.), except it doesn't connect over SSL. After much googling and much bothering on IRC, I have yet to find a way to get /dev/tcp to use SSL. Here is my current code:

#!/bin/bash

if [[ "$1" == "-debug" ]]; then
    set -x
fi

irc_send() {
    printf ">>> %s\n" "$1"
    printf "%s\r\n" "$1" >&3 &
}

sasl_successful() {
    while read -ru3 line; do
        printf "%s\n" "$line"
        read -r location numeric rest <<< "$line"

        if [[ "$numeric" == "903" ]]; then
            return 0
        elif [[ "$numeric" == "904" || "$numeric" == "906" ]]; then
            return 1
        fi
    done
}

sasl_connect() {
    user="$1"
    pass="$2"
    server_pass="$3"
    nick="$4"
    ident="$5"
    realname="$6"
    saslstring="$(printf '%s\0%s\0%s' "$user" "$user" "$pass" | base64)"

    irc_send "CAP REQ :sasl"

    if [[ "$server_pass" ]]; then
        irc_send "PASS $server_pass"
    fi

    irc_send "NICK $nick"
    irc_send "USER $ident * * :$realname"
    irc_send "AUTHENTICATE PLAIN"
    irc_send "AUTHENTICATE $saslstring"

    if sasl_successful; then
        irc_send "CAP END"
        return 0
    else
        return 1
    fi
}

get_title() {
    xmllint --html --xpath '//title/text()' - <<< "$(curl -sL "$1")" 2> /dev/null
}

domain_base() {
    domain="$(python -c "import urlparse; print urlparse.urlparse('$1').netloc")"

    if [[ -z "$domain" ]]; then
        echo "$1"
    else
        echo "$domain"
    fi
}

links=(
    'http://static.giantbomb.com/uploads/square_small/2/25062/833357-link_avatar3.jpg'
    'http://vignette1.wikia.nocookie.net/zelda/images/2/2a/Fierce_Deity_Link.png/revision/latest?cb=20100124002042'
    'http://8wayrun.com/attachments/lnksc2art2-jpg.3846/'
    'https://camo.githubusercontent.com/9bb56499161ec0a5c20b6b3a3af674f51072af7c/687474703a2f2f7777772e6e6f727468636173746c652e636f2e756b2f6775696c642f6172742f616e6e615f6c2f6c696e6b312e6a7067'
    'http://www.jdubuzz.com/files/2015/05/Link_3_ST.png'
    'http://www.smashbros.com/images/og/link.jpg'
    'https://upload.wikimedia.org/wikipedia/en/3/39/Wakerlink.jpg'
)

host="irc.freenode.net"
server_pass=""
port=6667
nick="mewtwo"
user="mewtwo"
realname="A simple irc bot written in bash."
channels="#somechannel"
username="$1"
password="$2"

exec 3<>"/dev/tcp/$host/$port"

if ! sasl_connect "$username" "$password" "$server_pass" "$nick" "$user" "$realname"; then
    printf "Could not connect.\n" >&2
fi

irc_send "JOIN $channels"

while :; do
    irc_send "PING $RANDOM"
    sleep 1m
done &

while read -ru3 line; do
    line="$(perl -pe 's/\r\n/\n/' <<< "$line")"
    read -r from type target msg <<<  "$line"
    msg="${msg#:}" nick="${from#:}" nick="${nick%%!*}" host="${from%%@*}" host="${from#"$host"@}"

    # parsing logic
    if [[ "$type" == "PRIVMSG" ]]; then
        printf "[%s] %s@%s: %s\n" "$target" "$nick" "$host" "$msg" &
    else
        printf "%s\n" "$line" &
    fi

    # response logic
    if [[ "$type" == "PRIVMSG" ]]; then
        if [[ "$msg" == "link?" ]]; then
            irc_send "PRIVMSG $target :${links[RANDOM % ${#links[@]}]}"
        fi

        urls=($(grep -oPm 1 '(?:https?:\/\/)?([a-z\d-]*\.)?[a-z\d-]+\.[a-z]+(?:\/\S*)?(?(?<=\.(jpg|png|gif))(*SKIP)(*F))' <<< "$msg"))

        for url in "${urls[@]}"; do
            irc_send "PRIVMSG $target :[$(get_title "$url")] - $(domain_base "$url")"
        done
    fi
done

Any suggestions are welcome!

like image 907
DTSCode Avatar asked May 16 '16 10:05

DTSCode


1 Answers

Open SSL socket with OpenSSL and talk to it with stdin stdout

openssl s_client irc.freenode.net:7070
like image 144
Léa Gris Avatar answered Nov 04 '22 20:11

Léa Gris