Skip to content

WordPress Upgrade 4.3 breaks wordpress cron wp-cron.php

WordPress Upgrade 4.3 breaks wordpress cron wp-cron.php published on No Comments on WordPress Upgrade 4.3 breaks wordpress cron wp-cron.php

There is a fresh bug in WordPress 4.3, it will cause a race condition in the wordpress cron, and the contents option_value of the option_name cron in wp_options will continue growing.

It will continue growing unchecked, this caused our binary log to fill up the disk.

You can check the size of the cron with:


mysql> select option_name,length(option_value) from wp_options where option_name ='cron';

If it continues growing unchecked you have hit the bug.
 
Here is the mailing list discussion of the bug:
http://lists.automattic.com/pipermail/wp-trac/2015-August/265144.html
 
Here is the changelist with the fixes for this bug
https://core.trac.wordpress.org/changeset/33647
 
If after applying the patch the old crontasks don’t get executed you may need to clear the cron:

mysql> UPDATE wp_options SET option_value = '' WHERE option_name = 'cron';

Starting mysqld and httpd on demand with xinetd

Starting mysqld and httpd on demand with xinetd published on 3 Comments on Starting mysqld and httpd on demand with xinetd

My father gave me an awesome present besides life ūüôā
He gave me a Raspberry Pi B model, its basically a low power consumption, low spec computer board, at a very low price intended for tinkerers, and electronic education.

I am using it to host my own PBX which is based of this project: Asterisk for raspberry
I am also using it for other purposes such as monitoring my home network as an active IDS, a dns server, a proxy, a vpn server, basically I want to use it for all the things you always wanted to have on a always-on server inside your house.

The problem I encountered was that the Pi model B comes with only 512 mb of RAM, and the Freepbx software uses Apache PHP5 and Mysql which consumes a good amount of RAM.
First step was easy, I just installed lighttpd and stopped apache. Second step I started looking into changing Freepbx to a SQLite engine, to get rid of MySQL, but Freepbx support for it was not 100%.

So after looking for a while I found a very nice solution for all my troubles, using xinetd and netcat (awesome tools) I start services on demand, when a connection comes in I start the required service and leave a background process to check on if the service is still required, if the port sees no further activity the service gets shutdown. So I can now have all the services that I want on the resource limited device.

I struggled to find how to do this. So I am sharing how I did it. I am also basing myself of this great post which does something similar but with another purpose in mind. Automatic Tunnels with xinetd and netcat.

Tools required:

  • xinetd
  • netcat
  • service httpd, mysqld
  • bash proxy script

This is my startup script I created here /etc/xinetd.init.d/lighttpd

  
#!/bin/bash
# inspired on this article
# https://www.linuxnet.ch/automatic-tunnels-with-xinetd-and-netcat/
# script is called from xinetd
# script starts and stops service using /etc/init.d scripts

SERVICE=/etc/init.d/lighttpd  # script used to start/stop service
PORT=81 # port where end service should listen
PID_FILE=/var/run/lighttpd.pid # pid file generated by init script
REAPER_PID_FILE="/var/run/lighttpd_reaper.pid" # pid file generated by this script
REAPER_SLEEP=180 # The reaper sleeps in seconds and checks for idle conns
LOG=/var/log/syslog # where to log messages

# this function checks if we already have reaper
check_reaper(){
        if  [ -s $REAPER_PID_FILE ]
        then
                reaper_pid=`cat $REAPER_PID_FILE 2>/dev/null`
                ps -p $reaper_pid &> /dev/null
                if [ $? -ne 0 ]
                then
                        start_reaper &    # If we dont have a reaper we start one
                        echo $! > $REAPER_PID_FILE
                fi
        else
                start_reaper &
                echo $! > $REAPER_PID_FILE
        fi

}

# this function starts a reaper, which is a background process that will kill the end service if its inactive
start_reaper(){
        while [ -f $PID_FILE ]
        do
                sleep $REAPER_SLEEP                                      # We wait
                touched=`stat --printf %W $REAPER_PID_FILE 2>/dev/null`  # We check when the reaper PID was last touched
                now=`date +%s 2>/dev/null`
                let idle=$now-$touched
                if [ $idle -gt $REAPER_SLEEP ]              # If reaper pid has not been touched in more than a sleep cycle we stop the service
                then
                        echo `date`" REAPER STOPPING SERVICE AFTER BEING $idle" >> $LOG   
                        $SERVICE stop >> $LOG               # This is the stop service instruction
                        rm $REAPER_PID_FILE 
                        exit 0
                fi
        done
}

# This is where we start our service
start_service(){
        sleep 1                    # Added a delay to trouble shoot as browsers kickstart several connections, we need to allow the PID file to be created this can be improved.
        if [ -s $PID_FILE ]        # We check if the PID file for the end service exist to avoid calling the start script when the service has already been started
        then
                return
        else
                echo `date`" STARTING $SERVICE" >> $LOG
                $SERVICE start &>> $LOG                  #this is the start service instruction
                return
        fi
}

# We probe and wait for the service to come on line
wait_for_service(){
        nc -w30 -z 127.0.0.1 $PORT &>/dev/null          # probe end port with a timeout of 30 seconds
        if [[ $? -ne 0 ]]
        then
                echo `date`" XINET SERVICE START ON $PORT TIMED OUT" >> $LOG
        fi
}

# This is were all the magic happens netcat passes traffic back and forth
transmit(){
        nc -w30 127.0.0.1 $PORT 2>/dev/null  # netcat is awesome, timeout flag of 30 seconds can be adjusted
}

# this is the main program that is called every time
main()
{
        nc -z 127.0.0.1 $PORT &>/dev/null  # We probe the end service
        if [[ $? -ne 0 ]]                  # If its not responding
        then
                start_service              # We start service
                wait_for_service           # We wait for service to became online
        fi
        check_reaper                       # We always check we have a reaper
        touch $REAPER_PID_FILE             # We log activity by touching the reaper PID file
        transmit                           # We transmit data 
        exit 0                             
}

main

This is the configuration for xinet.d

  
service http
{
        disable         = no
        socket_type     = stream
        protocol        = tcp
        port              = 80
        server = /etc/xinetd.init.d/lighttpd
        user            = root
        wait            = no
}

For mysqld I did something similar but I had to add a wait time as mysql takes longer to boot
mysql startup script I placed it in /etc/xinetd.init.d/mysqld
Another thing I encountered was that mysql clients tend to default to use the socket file, so I had to reconfigure so it would listen on the eth0 address, as a precaution I added a rule to only allow the same IP to access it, I can probably improve this too but I got it working like this.

 
#!/bin/bash
# inspired on this article
# https://www.linuxnet.ch/automatic-tunnels-with-xinetd-and-netcat/

SERVICE=/etc/init.d/mysql
PORT=3307
PID_FILE=/var/run/mysqld/mysqld.pid
REAPER_PID_FILE=/var/run/mysqld/mysqld_reaper.pid
REAPER_SLEEP=300
LOG=/var/log/syslog
IP='192.168.1.50'

check_reaper(){
        if  [ -s $REAPER_PID_FILE ]
        then
                reaper_pid=`cat $REAPER_PID_FILE 2>/dev/null`
                ps -p $reaper_pid &> /dev/null
                if [ $? -ne 0 ]
                then
                        start_reaper &
                        echo $! > $REAPER_PID_FILE
                fi
        else
                start_reaper &
                echo $! > $REAPER_PID_FILE
        fi

}

start_reaper(){
        while [ -f $PID_FILE ]
        do
                sleep $REAPER_SLEEP
                touched=`stat --printf %W $REAPER_PID_FILE 2>/dev/null`
                now=`date +%s 2>/dev/null`
                let idle=$now-$touched
                if [ $idle -gt $REAPER_SLEEP ]
                then
                        echo `date`" REAPER STOPPING SERVICE AFTER BEING $idle" >> $LOG
                        $SERVICE stop >> $LOG
                        rm $REAPER_PID_FILE
                        exit 0
                fi
        done
}

start_service(){
        if [ -s $PID_FILE ]
        then
                return
        else
                echo `date`" STARTING $SERVICE" >> $LOG
                $SERVICE start &>> $LOG
                return
        fi
}

wait_for_service(){
        sleep 10
        nc -w30 -z $IP $PORT &>/dev/null
        if [[ $? -ne 0 ]]
        then
                echo `date`" XINET SERVICE START ON $PORT TIMED OUT" >> $LOG
        fi
}

transmit(){
        nc -w30 $IP $PORT 2>/dev/null  # netcat is awesome

}

main()
{
        nc -z $IP $PORT &>/dev/null
        if [[ $? -ne 0 ]]
        then
                start_service &
                wait_for_service
        fi
        check_reaper &>/dev/null
        touch $REAPER_PID_FILE &>/dev/null
        transmit
        exit 0
}

main

And its xinet config file looks like this:
/etc/xinetd.d/mysqld

1
2
3
4
5
6
7
8
9
10
11
12
service mysql
{
        disable         = no
        type            = UNLISTED
        socket_type     = stream
        port              = 3306
        server = /etc/xinetd.init.d/mysqld
        user            = root
        wait            = no
        bind            = 192.168.1.50
        only_from       = 192.168.1.50
}

 

 

Telmex troncal SIP con Asterisk11

Telmex troncal SIP con Asterisk11 published on 11 Comments on Telmex troncal SIP con Asterisk11

Contrate una línea Telmex y me instalaron un gateway Thomson TG712, la línea telefónica que sale del teléfono ya no se conecta a la pared, se conecta a un puerto FXS en el módem.
Al parecer ya no instalan teléfonos analógicos, y de hecho Telmex empezó a ofrecer paquetes de solo Internet.

Lo primero que hice fue obtener los datos de la cuenta voip, esto lo hice en la pagina de configuración de voz del módem.

https://192.168.1.254/cgi/b/_voip_/cfg/?be=0&l0=4&l1=2

Le di editar y obtuve el Usuario, Contrase√Īa y SIP URI (En el caso de la contrase√Īa se puede obtener del codigo fuente de la pagina, o con un plugin para mostrar passwords en el navegador)

[email protected]¬†¬† y una contrase√Īa num√©rica 12345678901234

Buscando en internet lpi.telmex.com encontré este proxy 201.116.100.193

Probé los datos con un cliente zoipper y en un instante se conecto pude hacer y recibir llamadas de mi línea Telmex.

Configure una troncal en mi asterisk de la siguiente manera:

[[email protected]]
type=peer
insecure=invite,register
host=lpi.telmex.com
outboundproxy=201.116.100.193
[email protected]
secret=12345678901234
authdomain=lpi.telmex.com
[email protected]
fromuser=555XXXXXXX
fromdomain=lpi.telmex.com
context=from-trunk-sip-lpi.telmex.com

[lpi.telmex.com]
type=peer
host=lpi.telmex.com
outboundproxy=201.116.100.193
[email protected]
secret=122076218223
authdomain=lpi.telmex.com
fromuser=4496880517
fromdomain=lpi.telmex.com
[email protected]
context=from-trunk-sip-lpi.telmex.com

register=4496880517:[email protected]/4496880517

No tengo mucha experiencia en conmutadores y trate de configurarlo utilizando las instrucciones pero por m√°s que intente no se conectaba.

Capture y compare los paquetes de el zoipper con lo que mandaba el asterisk encontré 3 diferencias en la parte de Authorization:

 

  1. El campo de username= zoiper y thomson mandan username=”[email protected]”, Asterisk manda username=”555XXXXXXX” (sin el dominio, manda √ļnicamente el numero
  2. El campo de uri= zoiper y thomson mandan uri=”sip:lpi.telmex.com”
  3. El campo de cnonce= zoiper y thomson mandan un hash cnonce=”fbe4225b8d4a9aXX8f320d12ad6aX72X”, Asterisk manda solo unos cuantos caracteres cnonce=”478ce5d6″

Autenticación digest como lo envía asterisk

12:17:48.691772 IP (tos 0x60, ttl 64, id 1157, offset 0, flags [none], proto UDP (17), length 678)
127.0.0.1.sip > lpi.telmex.com.sip: SIP, length: 650
REGISTER sip:lpi.telmex.com SIP/2.0
Via: SIP/2.0/UDP 127.0.0.1:5060;branch=z9hG4bK5c8ebb6c
Max-Forwards: 70
From: ;tag=as7b5837f5
To:
Call-ID: [email protected]
CSeq: 103 REGISTER
User-Agent: FPBX-2.11.0beta2(11.1.0)
Authorization: Digest username=”555XXXXXXX”, realm=”ims.telmex.com”, algorithm=MD5, uri=”sip:sip:[email protected]”, nonce=”27902ec82235618e07f9a134c9599455″, response=”d43dee94422d68b246c1433748ed07ce”, qop=auth, cnonce=”478ce5d6″, nc=00000001
Expires: 120
Contact:
Content-Length: 0

La parte que no cuadra es esta:

Authorization: Digest username=”555XXXXXXX”, realm=”ims.telmex.com”, algorithm=MD5, uri=”sip:sip:[email protected]”, nonce=”27902ec82235618e07f9a134c9599455″, response=”d43dee94422d68b246c1433748ed07ce”, qop=auth, cnonce=”478ce5d6″, nc=00000001

Revisando el modulo chan_sip.c note que asterisk no calculaba los hashes para cnonce y el usuario le quitaba la parte despues del @.

Asi que modifique el modulo, la √ļnica funci√≥n que se necesita modificar es la de build_reply_digest Justo en la parte que tiene el comentario /* Calculate SIP digest response */

Ahí justo despues del comentario agregue el siguiente bloque de código para cuando la uri contenga Telmex cumpla con los requisitos del servidor:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
  if(telmex){
                char cnonce_hash[256];
                ast_md5_hash(cnonce_hash, cnonce);
                snprintf(a1, sizeof(a1), "%[email protected]:%s:%s", username, p->realm, secret);
                snprintf(a2, sizeof(a2), "%s:sip:lpi.telmex.com", sip_methods[method].text);
                if (!ast_strlen_zero(md5secret))
                        ast_copy_string(a1_hash, md5secret, sizeof(a1_hash));
                else
                        ast_md5_hash(a1_hash, a1);
                ast_md5_hash(a2_hash, a2);
 
                p->noncecount++;
                if (!ast_strlen_zero(p->qop))
                        snprintf(resp, sizeof(resp), "%s:%s:%08x:%s:%s:%s", a1_hash, p->nonce, p->noncecount, cnonce_hash, "auth", a2_hash);
                else
                        snprintf(resp, sizeof(resp), "%s:%s:%s", a1_hash, p->nonce, a2_hash);
                ast_md5_hash(resp_hash, resp);
 
                /* only include the opaque string if it's set */
                if (!ast_strlen_zero(p->opaque)) {
                        snprintf(opaque, sizeof(opaque), ", opaque="%s"", p->opaque);
                }
 
                /* XXX We hard code our qop to "auth" for now.  XXX */
                if (!ast_strlen_zero(p->qop))
                        snprintf(digest, digest_len, "Digest username="%[email protected]telmex.com", realm="%s", algorithm=MD5, uri="sip:lpi.telmex.com", nonce="%s", response="%s"%s, qop=auth, cnonce="%s", nc=%08x", username, p->realm, p->nonce, resp_hash, opaque, cnonce_hash, p->noncecount);
                else
                                        snprintf(digest, digest_len, "Digest username="%[email protected]telmex.com", realm="%s", algorithm=MD5, uri="sip:lpi.telmex.com", nonce="%s", response="%s"%s", username, p->realm, p->nonce, resp_hash, opaque);
 
                append_history(p, "AuthResp", "Auth response sent for %s in realm %s - nc %d", username, p->realm, p->noncecount);
 
                if (credentials) {
                        ao2_t_ref(credentials, -1, "Unref auth for digest");
                }
                return 0;
        }